Rust — What the Compiler Refuses
A Conversation With the Compiler
Goal
Learn what the Rust compiler blocks and why by reading its error messages. This lab has a step that deliberately makes the build fail, because that message is what you are here to learn.
Why it matters
What makes Rust hard is not the syntax but ownership. And the fastest way to learn ownership is to get blocked by the compiler.
The two things that block you are actually future bugs.
E0382(moved value): the incident of using freed memoryE0502(borrow conflict): the incident of reading an old pointer after a container has been reallocated
In C++ both pass silently, and strange values appear later.
Environment
There is no network, so cargo add does not work. This lab uses only the standard
library, so that is fine.
cargo build --offline 빌드
cargo run --offline 실행
cargo clippy --offline 더 나은 방법 제안
Steps
Create every file inside /root/work/own.
cargo init --name ownexamples/move_err.rs: fail on purpose →02-move.txtexamples/move_ok.rs: fix it by following the helpexamples/borrow_err.rs: fail on purpose →04-borrow.txtexamples/borrow_ok.rs: narrow the scope so it passes- Handle errors with
Result→06-result.txt - clippy →
07-clippy.txt - What was blocked and why →
08-notes.md
Why examples/? cargo build does not touch the examples.
If you put deliberately broken code there, the build of the whole project keeps passing.
Notes
- Read the error message to the end. The
help:line tells you how to fix it. - If you get stuck fighting ownership, it is fine to
clone()and move on. If performance becomes a problem, you fix it then. Trying to optimize with references from the start is the most common reason Rust feels hard.
Create the project
Create a cargo project in /root/work/own and make the empty project build successfully.
mkdir -p /root/work/own && cd /root/work/own && cargo init --name own. There is no network, so do not use cargo add; this lab uses only the standard library. Always add --offline: cargo build --offline.
Move on purpose and read the error
Write code that uses a value after it has been handed over in examples/move_err.rs, and save the full build error to 02-move.txt. The correct outcome of this step is a build failure.
Run mkdir -p examples, then write a main in examples/move_err.rs and inside it put let s = String::from("hi"); let t = s; println!("{} {}", s, t);. Then run cargo build --offline --example move_err > 02-move.txt 2>&1. You should see E0382 and 'moved'. The examples/ directory is not touched by cargo build, so it is fine to leave it broken.
Fix it as the compiler says
Write a version that does the same thing without an error in examples/move_ok.rs, and make it print both strings when run.
The help: line below the error message tells you how to fix it. Make it pass by copying with s.clone() or by borrowing with &s; both are correct. Run cargo run --offline --example move_ok.
Run into the borrow rule
Write code that calls push while a read borrow is alive in examples/borrow_err.rs, and save the error to 04-borrow.txt. Here too, the correct outcome is a failure.
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. You get E0502, which means a write borrow was requested while a read borrow was still alive.
Narrow the scope so it passes
Write a version that does the same thing but the build passes in examples/borrow_ok.rs. It must both push and print the first value.
A borrow lives only until its last use. If you finish using first before the push, the conflict disappears. Copying the value (let first = v[0];) is also correct, because i32 is Copy.
Handle errors with Result
Write fn half(n: i32) -> Result<i32, String> so that it returns Err for an odd number, and in main print both success and failure. Save the result to 06-result.txt.
Put it in src/main.rs and handle both branches with match half(n) { Ok(v) => ..., Err(e) => ... }. Do not use unwrap(); on failure it is a panic that kills the process. cargo run --offline > 06-result.txt 2>&1.
Ask clippy
Make cargo clippy --offline pass without warnings, and save the output to 07-clippy.txt.
Check by promoting warnings to errors with cargo clippy --offline --all-targets -- -D warnings > 07-clippy.txt 2>&1. The deliberately broken files in examples/ must be excluded, so instead of --all-targets look only at the default targets: cargo clippy --offline > 07-clippy.txt 2>&1. If it reports something, read what it points out and why, and fix it.
What was blocked and why
Summarize in three lines in 08-notes.md: what E0382 blocked, what E0502 blocked, and what incident would have happened at run time without those two.
Write both error codes in the text as they are. The third line is the key: the compiler showed you a future bug now (access to freed memory, an old pointer into a reallocated vector).