Ben Striegel

@bstrie

A Whirlwind Tour of Rust

SYSTEMS PROGRAMMING FOR THE MODERN DEVELOPER

// C
int sum = 0;
for (int i=0; i<x; i++) {
    sum += i;
}
# Python
sum = 0
for i in range(0, x):
    sum += i
# `sum()` ist verboten
// Rust
let mut sum = 0;
for i in 0..x {
    sum += i;
}

# Ruby
(0...x).inject(0) {|sum, i| sum + i}

# Python
reduce(lambda sum, i: sum + i,
    range(0, x), 0)

// Rust
(0..x).fold(0, |sum, i| sum + i)
; Assembly
lea	eax, [rdi - 1]
lea	ecx, [rdi - 2]
imul	rcx, rax
shr	rcx
lea	eax, [rcx + rdi - 1]
((x - 1) * (x - 2) >> 1) + x - 1
// Rust
(0..x).fold(0, |sum, i| sum + i)
// C, runtime memory error
int* foo() {
    int x = 4;
    return &x;
}
// Go, safe thanks to GC
func foo() *int {
    x := 4
    return &x
}
// Rust, does not compile
fn foo() -> &i32 {
    let x = 4;
    return &x;
}
// Go, with data race
x := 0
for i := 0; i < 10; i++ {
    go func() { x += 1 }()
}
// Go, without data race
mutex := &sync.Mutex{}
x := 0
for i := 0; i < 10; i++ {
    go func() {
        mutex.Lock()
        x += 1
        mutex.Unlock()
    }()
}
// Rust, does not compile
let mut x = 0;
for i in 0..10 {
    spawn(|| x += 1);
}
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
 --> race.rs:3:11
  |
3 |     spawn(|| x += 1);
  |           ^^ - `x` is borrowed here
  |           |
  |           may outlive borrowed value `x`
// Rust
let x = Arc::new(Mutex::new(0));
for i in 0..10 {
    let handle = x.clone();
    spawn(move || {
        *handle.lock().unwrap() += 1;
    });
}
// C
void foo() {
    int bar = 42;
}
// C
void foo() {
    char *ptr = (char*) malloc(42);
    free(ptr); // don't forget this!
}
// C
void foo() {
    char *ptr1 = (char*) malloc(42);
    char *ptr2 = ptr1;
    free(ptr1);
    free(ptr2); // what happens now?
}
// C
void foo() {
    char *ptr1 = (char*) malloc(42);
    char *ptr2 = ptr1;
    free(ptr1);
    char *ptr3 = (char*) malloc(42);
    free(ptr2); // what happens now?
}
// Rust
fn foo() {
    let ptr1 = String::new();
    let ptr2 = ptr1;
}
// Rust
fn foo() {
    let ptr1 = String::new();
    let ptr2 = ptr1;
    let ptr3 = ptr1; // doesn't compile!
}
error[E0382]: use of moved value: `ptr1`
 --> src/lib.rs:5:16
  |
3 |     let ptr1 = String::new();
  |         ---- move occurs because `ptr1` has type `String`,
  |              which does not implement the `Copy` trait
4 |     let ptr2 = ptr1;
  |                ---- value moved here
5 |     let ptr3 = ptr1;
  |                ^^^^ value used here after move
// C
void foo() {
    int bar = 42;
    int qux = bar;
    int ham = bar;
}
// Rust
fn foo() {
    let foo = 42;
    let qux = foo;
    let ham = foo;
}
// Rust
fn foo() {
    let ptr1 = String::new();
    let ptr2 = ptr1;
    let ptr3 = ptr1; // doesn't compile!
}
error[E0382]: use of moved value: `ptr1`
 --> src/lib.rs:5:16
  |
3 |     let ptr1 = String::new();
  |         ---- move occurs because `ptr1` has type `String`,
  |              which does not implement the `Copy` trait
4 |     let ptr2 = ptr1;
  |                ---- value moved here
5 |     let ptr3 = ptr1;
  |                ^^^^ value used here after move
// C
void foo() {
    char *ptr1 = (char*) malloc(42);
    char *ptr2 = ptr1;
    free(ptr1);
}
// Javascript
function foo() {
    let bar = [1, 2, 3];
    let qux = bar;
}
// C
void foo() {
    char *ptr1 = (char*) malloc(42);
    char *ptr2 = ptr1;
    // maybe use ptr2 somewhere in here
    free(ptr1);
}
// Rust
fn foo() {
    let own = String::new();
    let borrow = &own; // note the &
}
// Rust
fn foo() {
    let own = String::new();
    let borrow1 = &own;
    let borrow2 = &own;
}
// Rust
fn foo() {
    let own = String::new();
    let borrow = &own;
    borrow.push('x'); // doesn't compile!
}
error[E0596]: cannot borrow `*borrow` as mutable, as it is behind a `&` reference
 --> src/lib.rs:5:5
  |
5 |     borrow.push('x');
  |     ^^^^^^^^^^^^^^^^ `borrow` is a `&` reference,
  |                      so the data it refers to
  |                      cannot be borrowed as mutable
// Rust
fn foo() {
    let mut own = String::new();
    let borrow = &mut own;
    borrow.push('a');
}
// Rust, doesn't compile
fn foo() {
    let mut own = String::new();
    let borrow1 = &mut own;
    let borrow2 = &mut own;
    borrow1.push('a');
}
error[E0499]: cannot borrow `own` as mutable more than once at a time
 --> src/lib.rs:5:19
  |
4 |    let borrow1 = &mut own;
  |                  -------- first mutable borrow here
5 |    let borrow2 = &mut own;
  |                  ^^^^^^^^ second mutable borrow here
6 |    borrow1.push('a');
  |    ----------------- first borrow later used here
// Rust, doesn't compile
fn foo() {
    let mut vec = Vec::from([1, 2, 3, 4]);
    let borrow = &mut vec;
    for num in &vec {
        borrow.push(num);
    }
}
error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
 --> src/lib.rs:5:20
  |
4 |     let borrow = &mut vec;
  |                  -------- mutable borrow here
5 |     for num in &vec {
  |                ^^^^ immutable borrow here
6 |     borrow.push(num);
  |     ---------------- mutable borrow later used here
fn main() {
    let greeting = "hello";
    println!("{}, world", greeting);
}
struct Point {
    x: i32,
    y: i32
}

let point = Point { x: 12, y: 34 };

assert!(point.x + point.y == 46);
enum TrafficLight {
    Red,
    Yellow,
    Green
}

let current_light = Green;

match current_light {
    Red => println!("Stop!"),
    Yellow => println!("Slow down!"),
    Green => println!("Go!")
}
let foo = "Hello, world!".find(',');
assert!(foo == Some(5));

let bar = "Hello, world!".find('😎');
assert!(bar == None);
let foo: Result<i32, _> = "42".parse();
assert!(foo == Ok(42));

let bar: Result<i32, _> = "😎".parse();
assert!(bar.is_err());
let foo: i32 = "42".parse()?;

// Equivalent to:
let foo: i32 = match "42".parse() {
    Ok(num) => num,
    Err(e) => return Err(e)
};
// this works:
let foo;

if some_array.is_empty() {
    foo = "that array is empty!";
} else {
    foo = "no, it ain't!";
}

// or equivalently:
let foo = if some_array.is_empty() {
    "that array is empty!"
} else {
    "no, it ain't!"
};
struct Point { x: i32, y: i32 }

impl Point {
    fn new(x: i32, y: i32) -> Self {
        Point { x, y }
    }

    fn add_those_coords(&self) -> i32 {
        self.x + self.y
    }
}

let point = Point::new(12, 34);
assert!(point.add_those_coords() == 46);
trait PointTrait {
    fn new(x: i32, y: i32) -> Self;

    fn add_those_coords(&self) -> i32;
}

impl PointTrait for Point {
    fn new(x: i32, y: i32) -> Self {
        Point { x, y }
    }

    fn add_those_coords(&self) -> i32 {
        self.x + self.y
    }
}

www.rust-lang.org

Whirlwind Tour of Rust

By bstrie

Whirlwind Tour of Rust

  • 242