Skip to content

Latest commit

 

History

History
641 lines (466 loc) · 11.1 KB

File metadata and controls

641 lines (466 loc) · 11.1 KB
title The Rust Programming Language
author Rust Tutorial
theme dark
transition cycle
title_animation typewriter
code_theme base16-ocean.dark
margin 4
height 28
transition_duration 0.2

The Rust Programming Language

A systems language focused on safety, speed, and concurrency

Press Space or Right Arrow to advance


Why Rust?

Memory Safety - Performance - Zero-Cost Abstractions

  • Memory safe without garbage collection (ownership system)
  • Performance on par with C/C++, no runtime overhead
  • Concurrency without data races (compile-time guarantees)
  • Modern tooling: Cargo, rustfmt, clippy, rust-analyzer

Note

Rust has been voted "most admired language" for years. Adopted by Linux, Windows, Android, and Chromium kernels.


Rust vs Other Languages

title: Overall Score (Safety+Perf+Ecosystem)
labels: [Rust, C++, Go, Java, Python, Zig]
values: [95, 78, 82, 75, 68, 80]
height: 12

Installation

Install rustup

curl --proto '=https' \
  --tlsv1.2 -sSf \
  https://sh.rustup.rs | sh

Verify

rustc --version
cargo --version
rustup --version

Note

rustup manages multiple toolchains. Switch between stable, beta, and nightly easily.


Hello, World!

fn main() {
    println!("Hello, world!");
}

Build and run:

# Compile directly
rustc main.rs && ./main

# Using Cargo (recommended)
cargo new hello_rust
cd hello_rust && cargo run

Variables and Mutability

// Immutable by default
let x = 5;
// x = 6;  // ERROR: cannot assign twice

// Mutable variables
let mut y = 10;
y = 20;  // OK
// Constants (compile-time, type annotation required)
const MAX_POINTS: u32 = 100_000;

// Shadowing (re-declare with let)
let x = 5;
let x = x + 1;    // x = 6
let x = x * 2;    // x = 12

Primitive Data Types

Scalar Types

Type Examples
Integer i8 to i128
Unsigned u8 to u128
Float f32, f64
Boolean true, false
Char 'A', 'Z'

Compound Types

Type Examples
Tuple (i32, f64, bool)
Array [i32; 5]
Slice &[i32]
String String, &str

Functions

// Parameters require type annotations
// Return type declared with ->
fn add(a: i32, b: i32) -> i32 {
    a + b  // last expression = return value
}

// if is an expression (returns a value)
fn classify(n: i32) -> &'static str {
    if n > 0 { "positive" }
    else if n < 0 { "negative" }
    else { "zero" }
}

Note

Almost everything in Rust is an expression. if, match, and blocks {} can all return values.


Control Flow

// for loop (most common)
for i in 0..5 {
    println!("{}", i);  // 0,1,2,3,4
}

// while loop
let mut n = 3;
while n > 0 {
    n -= 1;
}

// loop: infinite, break returns a value
let result = loop {
    if n == 10 { break n * 2; }
    n += 1;
};

Ownership

The core concept that guarantees memory safety without GC

Three rules:

  1. Each value has exactly one owner
  2. There can only be one owner at a time
  3. When the owner goes out of scope, the value is dropped
let s1 = String::from("hello");
let s2 = s1;  // ownership MOVED to s2
// println!("{}", s1); // ERROR: s1 is invalid
println!("{}", s2);    // OK

Clone and Copy

// Deep copy (Clone) - heap data
let s1 = String::from("hello");
let s2 = s1.clone();  // s1 still valid

// Stack data: automatic Copy
let x = 5;
let y = x;    // x still valid
println!("x={}, y={}", x, y);

Note

Types implementing the Copy trait (integers, floats, booleans, chars, tuples of Copy types) are copied automatically on assignment. String, Vec do NOT Copy.


Borrowing: Immutable References

fn calculate_length(s: &String) -> usize {
    s.len()
    // s goes out of scope, but since it doesn't
    // have ownership, nothing happens
}

let s = String::from("hello");
let len = calculate_length(&s);
// s is still valid here
println!("{}: {} chars", s, len);
  • Multiple immutable references allowed simultaneously

Borrowing: Mutable References

fn append_world(s: &mut String) {
    s.push_str(", world!");
}

let mut s = String::from("hello");
append_world(&mut s);
println!("{}", s);  // "hello, world!"

Borrowing rules:

  • At any time: EITHER multiple &T OR one &mut T
  • References must always be valid (no dangling)

Caution

Violating borrowing rules causes compile errors, NOT runtime crashes. This is a feature!


Structs

struct User {
    name: String,
    email: String,
    active: bool,
}

impl User {
    fn new(name: &str, email: &str) -> Self {
        User {
            name: name.to_string(),
            email: email.to_string(),
            active: true,
        }
    }

    fn greet(&self) -> String {
        format!("Hi, I'm {}", self.name)
    }
}

Enums and Pattern Matching

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
    Triangle(f64, f64),
}

fn area(s: &Shape) -> f64 {
    match s {
        Shape::Circle(r) =>
            std::f64::consts::PI * r * r,
        Shape::Rectangle(w, h) => w * h,
        Shape::Triangle(b, h) => 0.5 * b * h,
    }
}

Note

match must be exhaustive: the compiler ensures every possible case is handled. Use _ for catch-all.


Option and Result

// Option<T>: values that might be absent
fn find_user(id: u32) -> Option<String> {
    if id == 1 { Some("Alice".into()) }
    else { None }
}

// Result<T, E>: operations that might fail
use std::fs;

fn read_config() -> Result<String, std::io::Error> {
    fs::read_to_string("config.toml")
}
// ? operator: concise error propagation
fn load() -> Result<String, std::io::Error> {
    let content = fs::read_to_string("a.txt")?;
    Ok(content.to_uppercase())
}

Traits

Defining shared behavior - the foundation of polymorphism

trait Summary {
    fn summarize(&self) -> String;

    // Default implementation
    fn preview(&self) -> String {
        format!("{}...", &self.summarize()[..20])
    }
}

struct Article { title: String, body: String }

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, self.body)
    }
}

Generics

// Generic function with trait bound
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut max = &list[0];
    for item in &list[1..] {
        if item > max { max = item; }
    }
    max
}
// Generic struct + trait bound
struct Point<T> { x: T, y: T }

impl<T: std::fmt::Display> Point<T> {
    fn show(&self) {
        println!("({}, {})", self.x, self.y);
    }
}

Lifetimes

// Lifetime annotations tell the compiler
// how long references are valid
fn longest<'a>(
    x: &'a str,
    y: &'a str,
) -> &'a str {
    if x.len() > y.len() { x } else { y }
}
// Structs holding references need lifetimes
struct Excerpt<'a> {
    part: &'a str,
}

let novel = String::from("Once upon a time...");
let first = novel.split('.').next().unwrap();
let e = Excerpt { part: first };

Closures and Iterators

// Closures: anonymous functions capturing env
let add = |a, b| a + b;
println!("{}", add(2, 3));  // 5

// Iterator chains: lazy, composable
let v = vec![1, 2, 3, 4, 5, 6];
let sum: i32 = v.iter()
    .filter(|&&x| x % 2 == 0)  // even
    .map(|&x| x * x)           // square
    .sum();                     // total
println!("{}", sum);  // 4+16+36 = 56

Note

Iterators are zero-cost abstractions: compiled code performs identically to hand-written loops.


Collections

Vec and String

let mut v = vec![1, 2, 3];
v.push(4);
v.pop();

let mut s = String::new();
s.push_str("hello");
s += " world";

HashMap

use std::collections::HashMap;

let mut m = HashMap::new();
m.insert("key", 42);

if let Some(v) = m.get("key") {
    println!("{}", v);
}

m.entry("new").or_insert(0);

Concurrency

use std::thread;
use std::sync::{Arc, Mutex};

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let c = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            *c.lock().unwrap() += 1;
        }));
    }

    for h in handles { h.join().unwrap(); }
    println!("{}", *counter.lock().unwrap());
}

Smart Pointers

Type Purpose
Box<T> Heap allocation, single owner
Rc<T> Reference counted, shared
Arc<T> Atomic ref count, thread-safe
RefCell<T> Runtime borrow checking
Mutex<T> Mutual exclusion lock
use std::rc::Rc;

let a = Rc::new(vec![1, 2, 3]);
let b = Rc::clone(&a);  // ref count + 1
println!("count = {}", Rc::strong_count(&a));
// count = 2

Cargo and Ecosystem

Command Description
cargo new Create new project
cargo build Build project
cargo run Build and run
cargo test Run tests
cargo doc Generate docs
cargo clippy Lint checks
cargo fmt Format code

Learning Roadmap

graph TD
A[Basic Syntax] --> B[Ownership]
B --> C[Structs and Enums]
C --> D[Traits and Generics]
D --> E{Advanced Path}
E -->|Systems| F[unsafe/FFI]
E -->|Web| G[Actix/Axum]
E -->|Async| H[tokio/async]
Loading

Client-Server Interaction

sequenceDiagram
    participant C as Client
    participant S as Server
    participant D as Database
    C->>S: HTTP Request
    S->>D: Query
    D-->>S: Results
    S-->>C: HTTP Response
Loading

Thank You!

Safe, Fast, Concurrent - Choose all three.