rust-logo.png

Introduction to Rust

Memory safety without garbage collection! Concurrency without Data Races! Abstraction without Overhead!

Why Rust?

Rust was designed to give the programmer as much direct control as C++, allowing:

...but without all the bugs that plague C++ programmers. Rust is safe:

Because it is C-ish in allocation, it doesn't need a runtime nor a garbage collector:

But if you do need unsafe features, they are available:

Getting Started

Rust is a systems programming language, so you compile source files into machine executables. Say hello:

hello.rs
fn main() {
    println!("hello");
}
$ rustc hello.rs && ./hello
hello

Loops, conditionals, and formatting:

triple.rs
fn main() {
    for c in 1..101 {
        for b in 1..c {
            for a in 1..b {
                if a * a + b * b == c * c {
                    println!("({}, {}, {})", a, b, c)
                }
            }
        }
    }
}
$ rustc triple.rs && ./triple
(3, 4, 5)
(6, 8, 10)
(5, 12, 13)
(9, 12, 15)
.
.
.
(54, 72, 90)
(35, 84, 91)
(57, 76, 95)
(65, 72, 97)
(60, 80, 100)
(28, 96, 100)

Command line arguments:

fib.rs
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        panic!("Exactly one command line argument required");
    }

    let n = match args[1].parse::<u32>() {
        Ok(v) => v,
        Err(e) => panic!("Command line arg must be nonnegative integer, {}", e)
    };

    let (mut prev, mut current) = (0, 1);
    while current <= n {
        print!("{} ", current);
        let next = prev + current;
        prev = current;
        current = next;
    }
    println!("")
}
$ rustc fib.rs && ./fib
task '<main>' failed at 'Command line argument required', fib.rs:6
$ ./fib 20000
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711
$./fib dog
task '<main>' failed at 'Command line argument must be a nonnegative integer', fib.rs:11

Phil Dorin's 180° clock hands problem:

clockhands.rs
fn main() {
    for i in 0..11 {
        let t = (((i as f64) + 0.5) * 43200.0 / 11.0) as i32;
        let h = t / 3600;
        let m = t % 3600;
        println!("{:02}:{:02}:{:02}", if h == 0 {12} else {h}, m / 60, m % 60);
    }
}

You can also use the Rust PlayPen for practice.

Learning Rust

Don't miss:

Here are some nice reviews (they might be a bit out of date, but still useful):

Types

TypeExampleNotes
i824i8-128...127
i16-30000i16-32768...32767
i320x33cc5a7bi32
i64
int
u8
u16
u32
u64
uint
f32
f64
()()Only value is ()
booltruetrue or false
char'å'4 bytes
str
tuple types
array types
struct types
enum types

Functions

Ownership and Borrowing

Data is owned by default. But there is region-based borrowing. Individual types can be marked as copy types. And there are (C++-style) destructors.

The big problem is the combination of aliasing with mutation. Can we separate those things?