Rust 소유권(Ownership)과 차용(Borrowing)

프로필 사진mingke

Rust ownership and borrowing

목차

소유권과 차용

최근에 취미로 Rust를 공부하고 있습니다. 러스트에는 소유권차용이라는 생소한 개념이 있더라구요. 공부한 내용을 이번 포스팅에서 정리해보려고 합니다. 이 개념들은 메모리 관리와 안전성을 강화하기 위해 설계된 것이라고 합니다.

소유권(Ownership)

소유권은 Rust에서 가장 중요한 개념중에 하나 입니다. 그 의미를 말 뜻에서 유추해 볼 수 있습니다. 어떤 하나의 값에 대해서 그 값에 대한 소유권을 가지는 변수는 한 개 입니다.

소유권은 각 데이터에 대해 소유자를 명확하게 해서 메모리 누수를 방지하고 dangling pointers 문제를 방지합니다.

그래서 소유자가 해당 스코프를 벗어나 버리면 값이 자동으로 해제됩니다. 이게 무슨 말인지 몰랐는데 코드로 보면 이해할 만 합니다.

  • 여기 Hello World 코드가 있습니다. 정상적으로 동작합니다.
fn main() {
    let s1:String = String::from("hello");
 
    println!("{}, world!", s1);
}
  • 다음과 같이 코드를 변경해보겠습니다.
 
fn main() {
    let s1:String = String::from("hello");
    let s2:String = s1;
 
    println!("{}, world!", s1); // 에러 발생
}
 

에러가 발생합니다. s1에 있던 hello의 소유권이 s2로 넘어가버렸기 때문에 s1은 더 이상 유효하지 않습니다. 에러를 보면 move라는 표현이 나오는데, 소유권이 이동(move)했다고 표현합니다.

// println!("{}, world!", s1);
//                         ^^ value borrowed here after move
  • 예제를 하나만 더 볼게요
fn main() {
    let s1:String = String::from("World");
 
    print_hello(s1);
 
    println!("Hello {} again", s1); // 이 코드 없으면 정상 동작
}
 
fn print_hello(value: String){
    println!("Hello, {}", value);
}

위 코드는 에러가 발생합니다. 단순하게 생각하면 main에 다른 변수가 없어서 소유권 이동이 없는 것처럼 보이지만 잘 보면 소유권이 print_hello 의 파라미터인 value로 이동했습니다. 따라서 s1은 소유권이 없어서 더 이상 사용을 못합니다.

차용(Borrowing)

마지막 예제에서 문제를 해결하기 위해 차용을 이용해 볼 수 있습니다. 차용도 소유권과 마찬가지로 단어 뜻에서 의미를 유추해 볼 수 있습니다. 소유권 이동없이 빌리는 것이라고 생각하면 쉬울 것 같습니다. 차용은 소유권 이전 없이 값에 대한 참조를 얻을 수 있는 방법입니다.

차용에는 가변 차용불변 차용이 있습니다.

불변 차용

불변 차용은 차용한 값을 변경할 수 없습니다. 마지막 예제를 불변 차용을 이용해서 해결할 수있습니다.

  • 코드를 약간 수정해야합니다. 참조는 &를 사용합니다.
fn main() {
    let s1: String = String::from("World");
 
    print_hello(&s1);
 
    println!("Hello {} again", s1);
}
 
fn print_hello(value: &String) {
    println!("Hello, {}", value);
}

가변 차용

가변 차용은 차용한 값을 변경할 수 있습니다. 위 예제를 살짝 변경해서 가변 차용을 해보도록 하겠습니다.

  • 가변 차용을 사용하기 위해 mut 키워드를 사용해야합니다.
  • mut 은 mutable의 줄임입니다.
  • !!!!!!!!!!!!! 를 넣어 인사를 강력하게 해보겠습니다.
fn main() {
    let mut s1: String = String::from("World");
 
    print_hello(&mut s1);
 
    println!("Hello {} again", s1);
}
 
fn print_hello(value: &mut String) {
    value.push_str("!!!!!!!!!!!!!");
    println!("Hello, {}", value);
}
 

value를 변경하여 강력한 인사를 하였습니다. 다만 s1의 값도 변경된 것을 확인할 수 있는데 그것은 values1이 같은 메모리 주소를 가리키고 있기 때문입니다.

마무리

소유권과 차용에 대해서 간단하게 공부해봤습니다. Python 개발자에겐 너무 생소한 개념이긴한데 또 공부해보니 못 할 정도는 아닌 것 같습니다. Rust로 Python라이브러리 개발해보고 싶은데 갈 길이 머네요.

Loading...