LabHub
배우기 러닝패스 코스

Rust — What the Compiler Refuses

A Conversation With the Compiler

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

Rust 컴파일러가 무엇을 왜 막는지를 오류 메시지를 읽으며 익힙니다. 이 실습에는 일부러 빌드를 실패시키는 단계가 있습니다 — 그 메시지가 배울 것이기 때문입니다.

왜 중요한가

Rust 를 어렵게 만드는 것은 문법이 아니라 소유권입니다. 그리고 소유권을 배우는 가장 빠른 길은 컴파일러에게 막혀 보는 것입니다.

막히는 두 가지가 실제로는 미래의 버그입니다.

C++ 에서는 둘 다 조용히 통과하고 나중에 이상한 값이 나옵니다.

환경

네트워크가 없어 cargo add 는 동작하지 않습니다. 이 실습은 표준 라이브러리만 쓰므로 상관없습니다.

cargo build --offline     빌드
cargo run --offline       실행
cargo clippy --offline    더 나은 방법 제안

단계

모든 파일은 /root/work/own 안에 만듭니다.

  1. cargo init --name own
  2. examples/move_err.rs — 일부러 실패 → 02-move.txt
  3. examples/move_ok.rs — help 를 따라 고치기
  4. examples/borrow_err.rs — 일부러 실패 → 04-borrow.txt
  5. examples/borrow_ok.rs — 범위를 좁혀 통과
  6. Result 로 에러 다루기 → 06-result.txt
  7. clippy → 07-clippy.txt
  8. 무엇이 막혔고 왜였는지 → 08-notes.md

examples/ 인가cargo build 는 examples 를 건드리지 않습니다. 일부러 깨뜨린 코드를 거기 두면 프로젝트 전체 빌드는 계속 통과합니다.

참고

프로젝트를 만든다

/root/work/own 에 cargo 프로젝트를 만들고 빈 상태로 빌드가 통과하게 하세요.

mkdir -p /root/work/own && cd /root/work/own && cargo init --name own. 네트워크가 없으니 cargo add 는 쓰지 마세요 — 이 실습은 표준 라이브러리만 씁니다. 항상 --offline 을 붙입니다: cargo build --offline.

일부러 옮겨 보고 오류를 읽는다

넘겨진 값을 다시 쓰는 코드를 examples/move_err.rs 에 쓰고, 빌드 오류 전문을 02-move.txt 로 남기세요. 이 단계의 정답은 빌드 실패입니다.

mkdir -p examplesexamples/move_err.rs 에 main 을 하나 쓰고 그 안에서 let s = String::from("hi"); let t = s; println!("{} {}", s, t);. 그다음 cargo build --offline --example move_err > 02-move.txt 2>&1. E0382 와 'moved' 가 보여야 합니다. examples/ 는 cargo build 가 건드리지 않으므로 깨진 채로 둬도 됩니다.

컴파일러가 말한 대로 고친다

같은 일을 오류 없이 해내는 판을 examples/move_ok.rs 에 쓰고, 실행하면 두 문자열이 찍히게 하세요.

오류 메시지 아래 help: 줄이 고치는 법을 알려 줍니다. s.clone() 으로 복사하거나 &s 로 빌려서 통과시키세요 — 둘 다 정답입니다. cargo run --offline --example move_ok.

빌림 규칙에 부딪혀 본다

읽기 빌림이 살아 있는 동안 push 를 하는 코드를 examples/borrow_err.rs 에 쓰고 오류를 04-borrow.txt 로 남기세요. 여기도 정답은 실패입니다.

let mut v = vec![1,2,3]; let first = &v[0]; v.push(4); println!("{}", first);cargo build --offline --example borrow_err > 04-borrow.txt 2>&1. E0502 가 나옵니다 — 읽기 빌림이 살아 있는데 쓰기 빌림을 요구했다는 뜻입니다.

범위를 좁혀 통과시킨다

같은 일을 하되 빌드가 통과하는 판을 examples/borrow_ok.rs 에 쓰세요. push 도 하고 첫 값도 출력해야 합니다.

빌림은 마지막으로 쓰인 지점까지만 삽니다. first 를 push 전에 다 쓰고 나면 충돌이 사라집니다. 값을 복사해 두는 것(let first = v[0];)도 정답입니다 — i32 는 Copy 니까요.

에러를 Result 로 다룬다

fn half(n: i32) -> Result<i32, String> 를 만들어 홀수면 Err 를 돌려주게 하고, main 에서 성공·실패 양쪽 모두를 출력하세요. 결과를 06-result.txt 로 남깁니다.

src/main.rs 에 넣고 match half(n) { Ok(v) => ..., Err(e) => ... } 로 두 갈래를 다 처리하세요. unwrap() 은 쓰지 마세요 — 그건 실패 시 프로세스를 죽이는 panic 입니다. cargo run --offline > 06-result.txt 2>&1.

clippy 에게 물어본다

cargo clippy --offline 이 경고 없이 통과하게 만들고 출력을 07-clippy.txt 로 남기세요.

cargo clippy --offline --all-targets -- -D warnings > 07-clippy.txt 2>&1 로 경고를 오류로 올려 확인합니다. examples/ 의 일부러 깨뜨린 파일은 제외해야 하니 --all-targets 대신 기본 대상만 보세요: cargo clippy --offline > 07-clippy.txt 2>&1. 지적이 나오면 무엇을 왜 지적하는지 읽고 고치세요.

무엇이 막혔고 왜였는지

08-notes.md 에 세 줄로 정리하세요 — E0382 가 막은 것, E0502 가 막은 것, 그리고 그 둘이 없었다면 실행 중에 어떤 사고가 났을지.

두 오류 코드를 본문에 그대로 적으세요. 세 번째 줄이 핵심입니다: 컴파일러가 미래의 버그를 지금 보여 준 것입니다 (해제된 메모리 접근, 재할당된 벡터의 옛 포인터).