Rust 기본 문법 - 변수, 데이터 타입, 함수, 소유권

lin·2023년 7월 21일
0

변수와 가변성

  1. Rust의 기본 변수는 불변성이다. 이를 통해 안전성과 동시성이라는 장점을 얻을 수 있다.
  2. 가변으로 바꾸고 싶으면 mut를 사용한다.
  3. 상수는 const로 선언한다.
  4. 변수는 Shadowing이 가능하다.
let x = 5;
let x = x + 1;
let x = String::from("hello");

mut를 사용하는 것과의 차이는 데이터 타입이 변경이 가능하다는 것이다.

데이터 타입들

스칼라 타입

하나의 값으로 표현되는 타입이다. => 정수형, 부동소수점 숫자, boolean, 문자

  • 정수형
    부호 있으면 i / 부호 없으면 u
    8 Bit, 16 bit, 32 bit, 64 bit, arch 길이가 있다.
  • 부동 소수점 타입
    f32, f64 -> 기본 타입은 f64
  • boolean
    모두가 아는 true, false
  • 문자 타입
    char!

복합 타입

  • Tuple
let tuple: (i32, f64, u8) = (500,6.4,1);

let (x, y, z) = tuple;
let five_hundred = tupre.0

튜플은 다양한 타입의 데이터를 집합시켜 하나의 복합 타입을 만든다.
괄호를 사용하며, 패턴 매칭을 사용하여 튜플의 값을 구조해체할 수 있다.
마침표와 인덱스를 사용하여 튜플의 요소에 직접 접근할 수 있다.

  • 배열
let a = [1,2,3,4,5];
let first = a[0];

배열의 길이는 가변적이지 않다!

함수

  • rust는 스네이크 케이스를 사용한다
    함수는 매개 변수를 가질 수 있고, 그 매개 변수를 위해 전달 인자를 전달할 수 있다.
    표현식을 통해서 결과 값을 산출해낼 수 있다.
fn msin() {
	print_function(5);
}

fn print_function(x : i32) {
	println!("hello, {}", x);
}

fn five() -> i32 {
	5
}

제어문

  • if문
    rust는 if식에 괄호를 안쓴다!
let condtion = true;

if condtion {
	println!("hello.");
}
  • for문
	let a = [1,2,3,4,5];
    
    for element in a.iter() {
    	println!(element.to_string());
    }

소유권

Rust는 시스템 프로그래밍 언어이다. 따라서 값이 힙에 있는지, 스택에 있는지에 따라 언어의 동작 방식에 영향을 많이 주게 된다!

스택과 힙은 런타임에 사용할 수 있는 메모리의 부분으로, 구조가 다르다.
Stack은 데이터를 접근하는 방식이 빠르다. 새로운 데이터를 넣을 공간을 찾을 필요가 없고 바로 top으로 가면 된다. 또 스택은 담긴 모든 데이터가 고정된 크기를 가지고 있어야 한다.

컴파일 타임에 크기가 결정되어 있지 않거나 크기가 변경될 수 있는 데이터를 위해서는 힙에 넣어야 한다.
공간있슈?라고 물어보면 운영체제가 빈 지점을 찾아서 할당을 해주고 포인터를 돌려준다.
실제 데이터를 사용할 때는 포인터를 따라가야 하는겨. 그래서 느리다!
힙데이터를 관리하기 위해 소유권이 필요함!

힙에 저장된 데이터는 소유권을 관리하고 빌려쓰고 참조한다.

String을 예를 들어서 생각해보면, String은 변경 가능하고 커질 수 있는 텍스트를 지원하기 위해 만들어졌다. 따라서 런타임에 운영체제로부터 메모리가 요청되어야 한다. + 러스트는 시이스템 프로그래밍 언어기때문에 메모리 반납까지 신경써줘야한다!
free()~~~!!

러스트에서는 메모리가 변수가 소속되어있는 스코프를 벗어나면 자동으로 반납된다.

  • 데이터와 변수의 상호작용
    별 거 없는 귀여운 데이터는 대입이라는 것이 쉽게 되지만
    String같은 친구들은 대입이 다른 언어랑 다르다. 주소를 가지고 찾아가는...
let s1 = String::from("hello
let s2 = s1; // 이때부터 s1는 해당 주소에 접근할 수 없다!

move occurs because s1 has type std::string::String

move가 일어난다. s2로 복사하면 s1은 무효화가 된다. 이동되었다!
만약 진짜 힙 데이터 자체까지 깊은 복사를 하길 원한다면 clone을 하면 된다.
하지만 비용이 많이 들어갈 수도 있다.
작고 귀여운 데이터 타입 즉 컴파일 타임에 결정되어있는 크기의 타입은 스택에 저장되기때문에 이동을 하지 않는다! 깊은 복사를 하나 얕은 복사를 하나 괜찮기때문이다.

소유권과 함수

함수에 값을 넣는건 변수에 대입하는 것과 같다. 따라서 이동하거나 복사될 것이다.
함수에 값을 사용하면서도 소유권을 주지않기 위해서는 참조자를 이용할 수 있다.

참조자를 인자로 사용하는 함수!

let s1 = String::from("hello");

let len = caluate_length(&s1);

fn calculate_length(s: &String) -> usize {
	s.len()
}

함수에 &s1를 넘기고 함수의 정의에도 &String을 사용했다! 이를 통해 어떤 값의 소유권을 넘기지 않고 참조할 수 있다. 빌린다! 변수는 원래 불변이구 따라서 참조하는 것을 변경할 수는 없다.

다만 가변 설정을 함수에 대해서는 건드릴 수 있다.
가변 참조자는 특정한 스코프 내에 딱 한번 생성할 수 있다.

  • 불변 참조자가 있으면 가변 참조를 할 수가 없다.
fn main() {
	let mut s = String::from("hello");
    
    change(&mut s);
}

fn change(some_string: &mut String){
	some.push_str(", world");
}
profile
BE

0개의 댓글