Thinking Different




소유권 개념

Rust에서는 소유권 개념이 존재합니다. 이는 Rust에서 사용되는 메모리의 관리체계로서 컴파일 타임에 컴파일러가 체크하여 관리되게 됩니다.

 

 

소유권 규칙

Rust에서는 값을 가지는 변수 또는 객체의 주체가 오직 1개만 갖도록 설계되어 있습니다. 그리고 스코프를 벗어나면 해지됩니다.

 

 

Rust에서의 스택과 힙 할당 방법

스택과 힙의 차이는 이미 아시리라 생각되어 별도로 설명하지 않겠습니다.

fn main()
{
    // stack
    let a = 10;
    let b = "hello";
    
    // heap
    let c = String::from("Rust");
}

 

 

String 타입의 Heap 할당

 

힙 방식의 메모리 할당은 c언어에서도 마찬가지로 사용되는 메모리 양이 커서 주체인 데이터(내용) 전체를 사용하지 않고 그 주소(포인터 : 4byte) 만을 이용하여 프로그램을 구동하므로 사용이 편리함에 있습니다. 또한 할당된 메모리 내에서는 자신이 필요한 만큼 늘이고 줄이고 사용이 가능한 것이죠.

 

아래 예제는 rust에서 사용되는 String 타입을 힙 메모리로 할당하여 사용되는 예제로서 소유권에 대한 개념입니다.

소유권 규칙에 보면 1개만 갖도록 되어있다고 했죠? 아래와 같이 소유권을 다른 변수에 넘기면 바로 그 직전 변수는 소유권이 접근 불가하게 됩니다.

 

fn main()
{
    let a = String::from("hello rust");
    let b = a;  // b에게 a의 소유권을 넘김(move: 이동)
    
    println!("{}", a); 
    // error[E0382]: borrow of moved value: `a`
    // 이미 소유권을 b에게 넘어갔으므로 a 접근 금지시킴
}

 

개인적으로 c언어를 오래동안 해왔던 저에게는 이해는 쉬웠지만 사용에는 꽤 어려움이 있었습니다. c언어나 기타 타 언어의 경우 소유권에 대한 개념이 없고 스코프 범위의 유효성(변수가 선언되고 '}' 스코프 끝이 나면 사라진다)만 존재하기 때문이죠.

rust를 배우면서 메모리의 위험성에 대해서 좀 더 많은 생각을 하게 되는건 맞는거 같습니다.

 

 

자 그럼 위에서는 소유권을 넘겨주어서 move 되었지만 copy 복사는 사용할 수 없는가? 입니다. 답은 가능하다 입니다.

String타입에 있는 clone() 함수를 통해서 복사가 가능합니다. 하지만 권장하지 않죠, 데이터가 방대하다면 복사하는데 리소스를 많이 잡아 먹어버려서 문제가 될 거니깐요.

 

코드로 보겠습니다. 아무 문제없이 컴파일 되고 실행됩니다. (단 데이터가 크다면 copy에 많은 연산시간과 리소스가 필요합니다)

fn main()
{
    let a = String::from("hello rust");
    let b = a.clone();  // b에게 a를 복사(copy)
    
    println!("{}, {}", a, b); 
}

 

 

Stack에만 있는 복사(Copy)

 

정수형과 같이 컴파일 타임에 결정되어 있는 크기의 타입은 스택에 모두 저장되기 때문에, 실제 값의 복사본이 빠르게 만들어질 수 있습니다.

 

다음 예제를 보죠, 아주 빠르고 복사가 잘됩니다.

fn main()
{
    let a = "hello rust";
    let b = a;
    
    let x = 10;
    let y = x;
    
    println!("{}, {}", a, b);
    println!("{}, {}", x, y);
}

 

 

함수 사용과의 소유권 관계

 

함수를 사용한 소유권 이동 및 해지되는 예제입니다. 위에서 배운 내용이므로 예제를 천천히 따라가보면 이해하기 쉽습니다.

fn main()
{
    // get_text 함수에서 문자열 객체 생성하여 소유권 얻어옴(move)
    let a = get_text();
    
    // print_text함수로 소유권 이동 (move)
    print_text(a);
    
    // print_text 함수에서 스코프를 벗어나 소유권 해지 되었으므로 오류
    // error[E0382]: borrow of moved value: `a`
    println!("{}", a);
}

fn get_text() -> String
{
    // 'Hello Rust' 생성하여 반환
    String::from("Hello Rust")
}

fn print_text(s: String)
{
    println!("{}", s);
    // s 소유권 해제
}

 

'프로그래밍 언어 > Rust' 카테고리의 다른 글

[Rust] 9. 슬라이스  (0) 2023.02.08
[Rust] 8. 참조자 (&)  (0) 2023.02.05
[Rust] 6. 제어문과 반복문 (if, loop, for, while)  (0) 2023.01.26
[Rust] 5. 주석  (0) 2023.01.26
[Rust] 4. 함수  (0) 2023.01.24