[Rust] &T, &mut T, 그리고 Copy

undefcat·2022년 11월 2일
0

rust

목록 보기
4/5
post-thumbnail

다음과 같은 코드를 보자.

let some_1 = Some(1);
let some_1_ref = &some_1;

let some_2 = some_1_ref.map(|one| one + 1);

위 코드는 문제없이 컴파일이 된다. 당연한가? 만약 아무런 이상함도 못느꼈다면, 다음과 같은 코드를 보자.

let some_1 = Some("1".to_string());
let some_1_ref = &some_1;

let some_2 = some_1_ref.map(|one| "two".to_string());

이 코드는 컴파일되지 않는다.

error[E0507]: cannot move out of `*some_1_ref` which is behind a shared reference
   --> src/first.rs:253:22
    |
253 |         let some_2 = some_1_ref.map(|one| "two".to_string());
    |                      ^^^^^^^^^^^----------------------------
    |                      |          |
    |                      |          `*some_1_ref` moved due to this method call
    |                      move occurs because `*some_1_ref` has type `Option<String>`, which does not implement the `Copy` trait
    |

Optionmapownership을 갖는다. 따라서, some_1_ref의 경우 shared reference이기 때문에 값을 move할 수 없다.

그런데 왜 첫번째 예제는 됐을까? shared reference여도 값이 move가 될 수 있는 경우가 있는데, 그건 바로 Copy trait가 구현되었을 때다. 즉, 첫번째 에제는 Copy trait을 구현하고 있다는 뜻이다.

Rust에서 Copy trait을 구현하고 있는 타입들로만 이루어진 값의 경우, 자동으로 Copy trait을 구현한다.

Option, i32Copy trait을 구현하고 있기 때문에 첫번째 예제는 컴파일이 된 것이다. 그 반면에, StringCopy trait를 구현하고 있지 않기 때문에 ownership을 해결해야 한다.

그래서 보통 Optionmap을 사용할 때 as_ref() 메서드를 활용한다. 이는 &Option<T>Option<&T>로 변환해주는 유용한 메서드다.

let some_1 = Some("1".to_string());
let some_1_ref = &some_1;

let some_2 = some_1_ref.as_ref().map(|one| "two".to_string());

이제 컴파일이 될 것이다.

그렇다면 다음과 같은 코드는 어떨까?

// some_1이 &String을 갖게 해보자.
let one = "1".to_string();
let some_1 = Some(&one);
let some_1_ref = &some_1;

let some_2 = some_1_ref.map(|one| "two".to_string());

이번엔 또 컴파일이 된다.

왜냐하면, Rust에서 &T 타입은 모두 Copy를 구현하기 때문이다. immutable reference이기 때문에 가능하다.

그렇다면 다음은 어떤가?

let mut one = "1".to_string();
// &mut 타입을 갖게 해보자
let some_1 = Some(&mut one);
let some_1_ref = &some_1;

let some_2 = some_1_ref.map(|one| "two".to_string());

이번엔 또 컴파일이 되지 않는다. &mut TCopy를 구현하지 않기 때문이다. mutable reference가 Copy를 구현한다면 여러 곳에서 이 값을 수정함을 허용한다는 뜻인데, 애초에 Rust는 이를 허용하지 않는다.

profile
undefined cat

0개의 댓글