LabHub

Rust — 컴파일러가 막는 것들 · 소유권과 빌림 · 이론

왜 두 번 쓰면 안 되는가

LabHub 에서 이어서 보기

한 줄 요약

Rust 는 값의 주인을 하나로 강제한다. 다른 곳에 넘기면 원래 자리에서는 못 쓴다. 그 규칙 하나가 GC 없이 메모리 안전을 만든다.

왜 이게 필요했나

C 계열의 대표적 사고 세 가지가 있다.

셋 다 "누가 이 값의 주인인가" 가 불분명해서 생긴다. GC 는 첫 두 개를 없애지만 멈춤 시간과 메모리 대가가 있고, 세 번째는 여전히 남는다.

Rust 는 다른 답을 골랐다 — 주인을 컴파일 시점에 추적한다. 실행 중 비용이 0이다.

규칙은 셋뿐이다

1. 모든 값에는 주인(owner)이 하나 있다
2. 주인이 사라지면 값도 사라진다
3. 값을 다른 곳에 넘기면(move) 원래 주인은 잃는다

let s = String::from("hi");let t = s;              // 주인이 t 로 옮겨졌다println!("{}", s);      // ❌ 컴파일 오류: s 는 이미 넘겨졌다

오류 메시지가 정확히 그렇게 말한다.

error[E0382]: borrow of moved value: `s`  = note: move occurs because `s` has type `String`,          which does not implement the `Copy` trait

Copy 를 구현한 타입은 복사된다. 정수·불리언·문자 같은 것들이다. 그래서 let a = 5; let b = a; 는 문제가 없다. 크기가 고정이고 힙을 안 쓰기 때문이다.

빌리기

넘기지 않고 잠깐 쓰려면 빌린다(borrow).

fn len(s: &String) -> usize { s.len() }   // 읽기만 빌림let s = String::from("hi");println!("{} {}", len(&s), s);            // ✅ s 는 여전히 내 것

빌림에는 규칙이 하나 더 있다.

> 읽기 빌림은 여러 개 동시에 되지만, 쓰기 빌림은 하나뿐이고 그동안 읽기도 못 한다.

let mut v = vec![1, 2, 3];let first = &v[0];      // 읽기 빌림v.push(4);              // ❌ 쓰기 빌림이 필요한데 읽기가 살아 있다println!("{}", first);

이게 막는 것은 실제 사고다. push 가 벡터를 재할당하면 first 가 가리키던 주소는 무효가 된다 — C++ 에서는 그게 조용히 통과하고 나중에 이상한 값을 읽는다.

수명

빌림은 원본보다 오래 살 수 없다. 컴파일러가 그걸 검사한다.

fn dangle() -> &String {          // ❌    let s = String::from("hi");    &s                            // s 는 함수가 끝나면 사라진다}

대부분의 경우 수명은 추론된다. 명시적으로 'a 를 쓰는 일은 생각보다 드물고, 주로 여러 참조 중 어느 것과 묶이는지를 알려 줄 때다.

흔한 착각

"clone 하면 되잖아" — 된다. 그리고 그게 맞는 답일 때도 많다. 소유권과 싸우느라 하루를 쓰느니 clone() 하고 넘어가는 편이 낫다. 성능이 문제가 되면 그때 프로파일러를 보고 고친다. 처음부터 참조로 최적화하려는 것이 Rust 를 어렵게 만드는 가장 흔한 이유다.

"unsafe 는 나쁘다"unsafe 는 "여기서는 컴파일러가 검사할 수 없으니 내가 보증한다" 는 표시다. 표준 라이브러리 안에도 많다. 나쁜 것은 unsafe 를 쓰는 것이 아니라 왜 안전한지 적지 않는 것이다.

실무에서 진짜 중요한 것

오류 메시지를 끝까지 읽는 습관이 Rust 학습의 절반이다. rustc 는 대개 고치는 방법까지 알려 준다.

help: consider cloning the value if the performance cost is acceptable   |5  |     let t = s.clone();   |              ++++++++

그리고 cargo clippy 는 컴파일은 되지만 더 나은 방법이 있는 곳을 짚어 준다. 배우는 동안에는 clippy 를 켜 두는 것이 책을 한 권 더 읽는 것과 비슷하다.