Why Rust, and Cargo Basics
Rust promises memory safety without a garbage collector — find out how, and meet the tool that makes every Rust project feel the same.
Every systems programmer eventually runs into the same wall: C and C++ give you total control over memory and hardware, but that control comes with landmines — use-after-free, double frees, buffer overflows, and data races that only show up under load, months after the code shipped. Garbage-collected languages like Java, Go, or Python sidestep those bugs by managing memory for you at runtime, but you pay for it with GC pauses, extra memory overhead, and less predictable performance — exactly what you don't want in a kernel module, a game engine, or a database. For decades that felt like a tradeoff you had to accept: fast and dangerous, or safe and slower.
Rust's core bet is that this tradeoff is a false one. Its ownership system — which you'll meet properly in lesson 3 — lets the compiler track, at compile time, exactly who is responsible for every piece of memory and exactly how long it stays valid. If your code would free memory twice, use it after it's gone, or let two threads mutate the same data without synchronization, Rust refuses to compile it. Nothing is checked at runtime, so there's no garbage collector and no performance penalty — the safety is baked into the type system itself.
This is why Rust gets described as enabling "fearless concurrency" and "fearless refactoring": the compiler is doing the review a careful senior engineer would do, on every single change, before the code ever runs. That's also why real, performance-critical projects have adopted it — parts of the Linux kernel, Firefox's rendering engine, big chunks of Dropbox's backend, and a large share of new command-line tools and WebAssembly modules are written in Rust today, not as an experiment but because it removes an entire category of production incidents.
None of that matters if the tooling is painful, so Rust ships Cargo — its build system, package manager, test runner, and documentation generator, all in one binary, present from your very first command. This is a deliberate departure from C and C++, where there's no standard way to declare a dependency or run a build; every project reinvents that wheel. In Rust, cargo new creates a working, buildable project in one command, and every Rust project you'll ever open — yours or a stranger's — follows the exact same layout.
Running cargo new hello_rust creates a folder with two things that matter: Cargo.toml, the manifest where your package's name, version, and dependencies live (think of it as package.json, but present from day one and central to the whole toolchain), and src/main.rs, where your actual code lives. Cargo also drops in a starter program for you — a main function that prints "Hello, world!" — so the very first thing you do with a new Rust project is successfully build and run it.
You have three commands for turning that code into something running, and picking the right one matters as your projects grow: cargo build compiles your code into a binary under target/debug without running it, cargo run does that and then immediately executes the result, and cargo check skips code generation and linking entirely, asking only "does this type-check and pass the borrow checker?" — which makes it dramatically faster and the command you'll run constantly while iterating, saving cargo run for when you actually want to see the program execute.
The last piece of the puzzle is the compiler itself. Rust's error messages are famous for being unusually helpful: they don't just say a line is wrong, they explain why in plain language, point at the exact span of code responsible, and often suggest the fix verbatim. Early on, you'll lean on the compiler as a teacher more than a gatekeeper — read every error message in full before you start guessing, because it's usually telling you precisely what to change.
fn main() {println!("Hello, world!");}
This is exactly what cargo new hello_rust writes into src/main.rs for you — a working program before you've typed a single line yourself.
fn main() {let language = "Rust";let year = 2015;println!("{} reached 1.0 in {}.", language, year);}
cargo run compiles and immediately executes this in one step; format arguments inside println! are filled in from left to right by position.
fn greet(name: String) -> String {format!("Hello, {}!", name)}fn main() {let message = greet(String::from("Ferris"));println!("{}", message);}
A function with an explicit parameter and return type, plus a call from main — the same shape you'll use in every Rust program from here on, still using only owned String values.
🧠 Check your understanding
0/1 · 0/1 answered1. You're in the middle of writing a function and just want to know if it compiles before you keep going. Why would you reach for cargo check instead of cargo build?