Rust Basics #1 What Rust Is: Why Learn It, Installing rustup, First Steps with cargo
Announcements of new developer tools these days keep including the same sentence: “written in Rust.” The Python package manager uv and the search tool ripgrep are CLI examples, and parts of the Linux kernel, Windows, and Android are being written in Rust as well. This series learns that Rust from the ground up in nine parts. We start with variables and types, cross the language’s heart — ownership and borrowing — then climb through structs and enums, error handling, collections and iterators, traits and generics, up to lifetimes and modules. The assumed reader is not someone completely new to programming, but a developer who has used at least one language like Python or JavaScript.
The problem Rust solved: safety or performance, pick one #
Before Rust, languages had to choose one of two answers to memory management.
- Leave it to a garbage collector (GC): Python, JavaScript, and Go are on this side. Developers don’t have to think about memory, but they accept the cost of a runtime doing that work and the pauses when the GC steps in.
- Manage it by hand: C and C++ are on this side. Performance is maximal, but reusing freed memory (use-after-free) or reading past a boundary is entirely the developer’s responsibility. When Microsoft and the Chrome team each analyzed their own security vulnerabilities, the famous result was that about 70% were memory bugs of this kind.
Rust’s answer is a third way: check who frees memory, and when, at compile time. Instead of a GC running at runtime, the compiler looks at the code and determines in advance that “this value is freed at this point.” That is how Rust delivers C-level performance while an entire class of memory bugs is filtered out at the compile stage. The rules behind this check are ownership, the subject of Part 3.
There is a price, of course. Code that violates the ownership rules simply does not compile, so the first few weeks tend to feel like “fighting the compiler.” The goal of this course is to make that fight as short as possible. Once you understand why the rules exist, the compiler stops being an enemy and becomes a reviewer that catches bugs before deployment.
Installation: one line of rustup #
Rust’s official installer is rustup. It installs the compiler (rustc), the build tool (cargo), and documentation in one go, and manages versions afterwards.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shThat is for macOS and Linux; on Windows, download and run rustup-init.exe from the official rustup site. When it finishes, two commands confirm the install.
rustc --version
cargo --versionRust ships a new stable release every six weeks, and rustup update is all it takes to move up. Versions climb quickly, but backward compatibility is strict, so there is little risk of examples breaking across versions. This course is written against the current standard, the 2024 edition.
cargo: the beginning and end of every project #
In practice you almost never invoke rustc directly. Project creation, building, running, and dependency management are all cargo’s job.
cargo new hello
cd hello
cargo runThe structure cargo new creates has only two parts.
hello/
├── Cargo.toml ← package metadata and dependencies
└── src/
└── main.rs ← source code entry point[package]
name = "hello"
version = "0.1.0"
edition = "2024"Three commands are enough to get going. cargo run builds and runs, cargo build only builds, and cargo check runs the compile checks without producing an executable. Rust is a language where you see compile errors often, so running cargo check after every change quickly becomes the basic rhythm.
A first program, and a first compile error #
fn main() {
let name = "Rust";
println!("Hello, {name}!");
}fn main is the entry point, and the exclamation mark in println! marks it as a macro rather than a function. So far this looks like any other language. To see the Rust-specific part, let’s cause an error on purpose.
fn main() {
let count = 1;
count = 2; // compile error
}error[E0384]: cannot assign twice to immutable variable `count`
--> src/main.rs:3:5
|
2 | let count = 1;
| ----- first assignment to `count`
3 | count = 2;
| ^^^^^^^^^ cannot assign twice to immutable variable
|
help: consider making this binding mutable: `mut count`The first rule is that variables declared with let are immutable by default — but what deserves attention right now is the error message itself. It tells you where the problem is, why it is a problem, and how to fix it (the help line). Half of learning Rust is building the habit of reading these messages. If you are curious about an error code, rustc --explain E0384 shows a detailed explanation with examples.
Summary #
- Rust guarantees memory safety without a GC. The core is the ownership rules that fix the moment of deallocation at compile time rather than runtime, which is how it gets C-level performance and a whole class of memory bugs blocked at once.
- The price is the learning curve. Code that breaks the rules doesn’t compile — but that means crashes after deployment are pulled forward into compile errors.
- Installation is one line of rustup, and cargo handles everything about a project.
cargo new,cargo run, andcargo checkare the basic rhythm. - Error messages carry the cause and the fix. Together with
rustc --explain, reading them carefully is the fastest way to learn. - The next part covers variables and types:
letwith immutability by default, shadowing, and Rust’s distinctive rule that functions end in expressions.