Ownership

Doosan published on
2 min, 361 words

Categories: Post

Ownership Rules

  1. Rust의 모든 값에는 owner가 있다.
  2. 한 번에 owner는 하나만 존재할 수 있다.
  3. owner가 scope 밖으로 나가면 값은 drop된다.

ownership rule을 따르려면 몇 가지 개념을 구분해야 한다. C# 개발자 입장에서 가장 헷갈렸던 것은 아래 세 가지였다.

Copy

let x = 5;
let y = x;

Move

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

Borrow

let mut s = String::from("hello");

let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{r1} and {r2}");
// Variables r1 and r2 will not be used after this point.

let r3 = &mut s; // no problem
println!("{r3}");

Copy

The Book의 예제를 읽을 때는 이해한 것 같았다. 하지만 실제로 코딩을 시작하니 copy, borrow, move가 계속 헷갈렸다. 최근 C# 코드를 작성하다가 내가 왜 이 셋을 헷갈렸는지 깨달았다.

아래 예제는 며칠 전 실제로 코딩하다가 만난 문제와 비슷하다.

public class Apple{
    public string Name{get;set;}
    public int Total{get;set;}
    public Apple(string name, int qty){
        Name=name;
        Total=qty;
    }
}
public class Store{
    public Queue<Apple> AppleBasckets {get;set;}
    public Store(){
        AppleBasckets = new Queue<Apple>();
    }
    public Apple Take(int quantity){
        Apple result = null;
        if(AppleBasckets.TryPeek(out var apple)){
            if(apple.Name == "Fuji")
            {
                result = apple;
                apple.Total -= quantity;
            }
        }
        return result;
    }
}
public static void Main(string[] args)
{
    var store = new Store();
    store.AppleBasckets.Enqueue(new Apple("Fuji",40));
    store.AppleBasckets.Enqueue(new Apple("Ambrosia",20));

    var result = store.Take(5);
    Console.WriteLine(result.Total);
}

콘솔에는 35가 출력된다. 나는 무의식적으로 assignment operator(=)가 copy를 의미한다고 생각하고 있었다. result = apple;을 할 때 apple의 값을 result로 복사하고 싶었지만, 실제로는 object data가 아니라 reference만 복사됐다. 그래서 의도치 않게 원본 객체가 수정됐다.

Rust 식으로 생각하면 이 상황은 "같은 데이터를 여러 변수가 가리키고 있고, 그중 하나를 통해 값을 변경했다"에 가깝다. C#에서 객체 자체를 복사하고 싶다면 ICloneable을 구현하거나 별도의 copy 로직을 작성해야 한다.

Move

위 C# 코드에서는 하나의 데이터를 두 변수가 참조했다. 아래 그림으로 보면 Figure 1-1에 해당한다. Rust는 ownership model을 따르기 때문에 Figure 1-3처럼 데이터를 다룬다.

Description

[Figure 1-1]: 데이터 1개, owner 2개처럼 보이는 상태

Description

[Figure 1-2]: 데이터 2개, owner 2개

Description

[Figure 1-3]: 데이터 1개, owner 1개

*위 이미지는 모두 The Rust Programming Language에서 가져왔다.

배운 점

assignment operator(=)를 볼 때마다 이 연산이 실제 데이터를 복사하는지, reference만 복사하는지, 아니면 ownership을 move하는지 먼저 생각해야 한다. C#, JavaScript, Rust 모두 이 차이를 의식해야 한다.