Skip to main content
Rust beginner Lesson 1 of 30

Introduction to Rust

Learn what Rust is, why it matters, and where it excels — memory safety without a garbage collector.

What is Rust?

Rust is a systems programming language created at Mozilla Research and released in 2015. Its core promise is a trifecta that was previously considered impossible to achieve simultaneously: memory safety, thread safety, and performance on par with C/C++ — all without a garbage collector. Understanding this trifecta is the key to understanding why Rust exists and why it has grown so rapidly.

The language enforces its guarantees at compile time through an ownership system. Every value has exactly one owner. When the owner goes out of scope the value is freed automatically — no runtime overhead, no dangling pointers, no use-after-free bugs, no data races. The compiler rejects any program that would violate these rules, so entire classes of bugs are impossible by construction.

fn main() {
    let s = String::from("hello"); // s owns the string data on the heap
    println!("{}", s);
} // s goes out of scope here — memory is freed automatically, no free() needed

Why Rust Instead of C/C++?

C and C++ give you raw control but place the entire burden of memory safety on the programmer. A missing free, a double-free, or a buffer overrun can silently corrupt memory and create exploitable security vulnerabilities. These classes of bugs account for roughly 70% of CVEs in major browsers and operating systems — and they have persisted for decades despite better tooling, because the language itself offers no structural protection.

Rust’s compiler refuses to compile code that could exhibit undefined behaviour. The safety guarantee is not a runtime check — it is a compile-time proof. If the program compiles, an entire category of memory bugs simply cannot occur.

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();
    for (i, &byte) in bytes.iter().enumerate() {
        if byte == b' ' {
            return &s[0..i]; // returns a slice — a borrow of s
        }
    }
    &s[..]
}

fn main() {
    let mut s = String::from("hello world");
    let word = first_word(&s);  // word borrows s
    // s.clear();  // ERROR: cannot mutate s while word (a borrow) is alive
    println!("first word: {}", word);
}

Uncomment s.clear() and the compiler rejects the program — you can never hold a reference to freed or mutated data.

Why Rust Instead of Go / Java / Python?

Garbage-collected languages solve memory safety by periodically pausing the program or running a background collector. That runtime overhead matters in several important contexts:

  • Latency-sensitive services — GC pauses create unpredictable jitter that breaks tight SLA requirements.
  • Embedded / bare-metal — There is no runtime environment to host a garbage collector.
  • WebAssembly — Binary size and startup time are critical; a GC runtime bloats both.
  • OS kernels / drivers — You need full, deterministic control over every allocation and deallocation.

Rust fits all of these contexts while still offering high-level abstractions like iterators, closures, generics, and async/await — so you don’t give up expressiveness to get performance.

Key Language Features

Understanding these features at a high level will help you make sense of the tutorials that follow. Each one is covered in depth in its own section.

FeatureWhat it means
OwnershipEach value has exactly one owner; freed when owner drops
BorrowingReferences allow temporary access without transferring ownership
LifetimesCompiler tracks how long references are valid
TraitsRust’s interface / typeclass system
Enums + pattern matchingAlgebraic data types with exhaustive matching
Zero-cost abstractionsHigh-level code compiles to the same machine code as hand-written low-level code
cargoIntegrated build system, package manager, test runner, and documentation generator

Where Rust Is Used Today

Rust has moved well beyond research and into production at some of the world’s largest software companies. These real-world deployments are a testament to both the language’s maturity and the practical value of its guarantees.

  • Firefox — large parts of the browser engine (Servo project)
  • Linux kernel — Rust is now an officially supported language for kernel modules
  • AWS — Firecracker VMM (powers Lambda and Fargate) is written in Rust
  • Cloudflare — network proxies and edge workers
  • Discord — replaced Go services for lower latency and memory use
  • Microsoft — rewriting Windows components to eliminate memory-safety bugs
  • Dropbox — storage backend
  • WebAssembly toolchainwasm-pack, wasm-bindgen

The Rust Ecosystem

Rust ships with a complete, well-integrated toolchain. You rarely need to reach for third-party tools for common tasks — the official tooling covers the vast majority of the development workflow.

rustup      — toolchain installer and version manager
cargo       — build system and package manager
crates.io   — package registry (like npm or PyPI)
docs.rs     — auto-generated documentation for every crate
rust-analyzer — LSP server for IDE support
clippy      — opinionated linter
rustfmt     — automatic code formatter

Popular crates you will encounter early:

  • serde — serialization/deserialization (JSON, TOML, YAML…)
  • tokio — async runtime
  • reqwest — HTTP client
  • clap — CLI argument parsing
  • anyhow / thiserror — ergonomic error handling
  • rayon — data parallelism

A Taste of Idiomatic Rust

Before diving into each topic, here is a short program that uses several Rust idioms together. Don’t worry if not every detail is clear yet — the goal is to see what idiomatic Rust looks like so you have a target in mind as you work through the tutorials.

use std::collections::HashMap;

// Accepts a &str (borrowed string slice), returns an owned HashMap
fn word_count(text: &str) -> HashMap<&str, usize> {
    let mut counts = HashMap::new();
    for word in text.split_whitespace() {
        // entry API: insert 0 if absent, then increment
        *counts.entry(word).or_insert(0) += 1;
    }
    counts
}

fn main() {
    let text = "the quick brown fox jumps over the lazy dog the fox";
    let counts = word_count(text);

    // Collect into a Vec so we can sort by count (descending)
    let mut pairs: Vec<(&&str, &usize)> = counts.iter().collect();
    pairs.sort_by(|a, b| b.1.cmp(a.1));

    for (word, count) in pairs.iter().take(3) {
        println!("{}: {}", word, count);
    }
}
// Output:
// the: 3
// fox: 2
// quick: 1  (or any other word with count 1)

This snippet demonstrates borrowing, iterators, generics, and the entry API — all core Rust idioms you will learn in depth throughout this tutorial series.

Next Steps

The tutorials in this series are ordered to build concepts on top of each other. Start with Setup to install Rust, then work through variables, types, and control flow before tackling ownership — the concept that makes Rust unique. Each tutorial assumes you have read the ones before it.

Frequently Asked Questions

Is Rust hard to learn?
Rust has a steep initial curve due to ownership and the borrow checker, but the concepts become natural with practice. Most developers find it rewarding once the model clicks.
Does Rust have a garbage collector?
No. Rust uses an ownership system with compile-time checks to manage memory deterministically, giving you GC-like safety with C-like performance.
What is Rust mainly used for?
Systems programming, WebAssembly, CLI tools, network services, game engines, embedded firmware, and anywhere performance and reliability both matter.