C.W.K.
Stream
Lesson 03 of 05 · published

빌림 규칙 & borrow checker

~12 min · borrowing, borrow-checker, nll

Level 0Rust 호기심러
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

빌림 규칙을 조각조각 만났어. 깔끔하게 정리하고, 그걸 강제하는 컴파일러의 부분을 만나보자: borrow checker.

두 규칙

하나: 어느 순간이든 가변 참조 하나 OR 불변 참조 몇 개든 가질 수 있어. 둘: 참조는 항상 유효해야 해 — 가리키는 데이터보다 오래 살 수 없어. 그게 borrow checker 전부야, 두 문장으로. 나머지는 다 컴파일러가 네 코드가 이걸 지키는지 증명하는 거야.

참조는 스코프 끝이 아니라 마지막 사용까지 산다

현대 Rust 는 똑똑해: 참조의 borrow 는 닫는 중괄호가 아니라 마지막 사용 에서 끝나. 그래서 불변 borrow 를 만들고, 다 쓰고, 그다음 같은 스코프에서 가변 borrow 를 잡을 수 있어. 이걸 non-lexical lifetimes (NLL) 라 부르고, 실패할 것 같은 코드가 실제론 컴파일되는 이유야.

borrow 에러가 헷갈리면 마지막 사용을 찾아. borrow 는 생성부터 마지막 사용까지 살아. 종종 수정은 그냥 순서 바꾸기야: 가변을 잡기 전에 불변 참조를 다 쓰면 충돌이 사라져.

borrow checker 는 린터가 아니라 증명기야

추측하거나 경고하지 않아 — 모든 참조에 대해 데이터가 그보다 오래 살고 aliasing 규칙이 지켜진다는 걸 증명 해. 안전을 증명 못 하면 코드를 거부하고. 그게 컴파일되는 Rust 프로그램에 use-after-free 도 데이터 레이스도 없는 이유야: '아마' 가 아니라 증명됨.

맞서 싸우는 건 한 단계야

초반엔 borrow checker 랑 싸우는 기분이 들 거야. 나중엔 네가 못 보던 진짜 aliasing 위험을 잡아주던 거였다는 걸 깨달아. 규칙은 안 바뀌어; 네 직관이 거기 따라잡는 거야. 그 전환이 이 퀘스트가 컴파일러를 멘토로 그리는 이유 전부야.

Code

Non-lexical lifetimes: 마지막 사용이 borrow 를 끝낸다·rust
fn main() {
    let mut v = vec![1, 2, 3];

    let first = &v[0];     // 불변 borrow 시작
    println!("{first}");   // ...그리고 여기, 마지막 사용에서 끝남

    v.push(4);             // 이제 가변 borrow 허용 — 충돌 없음
    println!("{v:?}");

    // v.push(4) 뒤에 `first` 를 썼다면 그건 E0502:
    // 불변 borrow 가 수정 동안 아직 살아있을 테니까.
}

External links

Exercise

벡터로의 불변 참조를 잡아 println 에 쓰고, 그 뒤에 벡터를 수정하는 코드를 써봐 — NLL 덕에 컴파일되는 걸 확인해. 그다음 println 을 수정 *뒤로* 옮기고 같은 코드가 컴파일 안 되는 걸 봐. borrow 가 왜 이제 겹치는지 설명해봐.
Hint
NLL 은 불변 borrow 를 마지막 사용에서 끝내. 그 사용을 수정 뒤로 옮기면 borrow 의 수명이 수정을 가로질러 — 그게 E0502 가 보고하는 겹침이야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.