Top Banner
Nicholas Matsakis Mozilla Research
61

Rust tutorial from Boston Meetup 2015-07-22

Apr 13, 2017

Download

Software

nikomatsakis
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Rust tutorial from Boston Meetup 2015-07-22

Nicholas Matsakis!Mozilla Research

Page 2: Rust tutorial from Boston Meetup 2015-07-22

So, you want more control?

C++?

OMG!

2

Too slow!

Other things you might want:! • Standalone library, as you would get from C • Interface with another runtime, e.g. Ruby   • Use a really cool language :)

Page 3: Rust tutorial from Boston Meetup 2015-07-22

My god, it’s full of bugs

3

Dangling pointers !Segmentation faults !Double frees !Uninitialized data !Null pointer exceptions !Resource leaks (DB handle) !Data races

Solved by GC

Not so much.

Page 4: Rust tutorial from Boston Meetup 2015-07-22

4

Systems programming without the hasslecrashes!heisenbugs!fear

Parallel!

Page 5: Rust tutorial from Boston Meetup 2015-07-22

// sums all the positive values in `v` fn sum_pos(v: &Vec<i32>) -> i32 { let mut sum = 0; for i in v.iter().filter(|i| **i > 0) { sum += *i; } sum }

High-level coding

5

Iterators.

Closures.

Page 6: Rust tutorial from Boston Meetup 2015-07-22

Assembly code

6

leaq (%rdi,%rsi,4), %rcx xorl %eax, %eax jmp .LBB5_1 .LBB5_3: addl %edx, %eax .align 16, 0x90 .LBB5_1: cmpq %rdi, %rcx je .LBB5_4 movl (%rdi), %edx addq $4, %rdi testl %edx, %edx jle .LBB5_1 jmp .LBB5_3 .LBB5_4: retq

Page 7: Rust tutorial from Boston Meetup 2015-07-22

fn foo(v: &Vec<i32>) -> i32 { v.iter() .filter(|i| **i > 0) .map(|i| *i) .sum() }

Higher-level coding

7

…generates the same assembly code.

Page 8: Rust tutorial from Boston Meetup 2015-07-22

Safe

8

fn this_wont_compile(v: &mut Vec<i32>) -> i32 { let mut sum = 0; for &i in v.iter() { sum += i; if i > 0 { v.push(0); } } sum }

error: cannot borrow `*v` as mutable because it is also borrowed as immutable if i > 0 { v.push(0); } ^ note: previous borrow of `*v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `*v` until the borrow ends for &i in v.iter() { ^

Might free underlying buffer.

Page 9: Rust tutorial from Boston Meetup 2015-07-22

Parallel

9

use std::thread; fn qsort(data: &mut [i32]) if data.len() <= 1 { return; } let mid = partition(data[0], data); let (left, right) = data.split_at_mut(mid); let t1 = thread::scoped(|| qsort(left)); qsort(right); }

Sort left and right in parallel.Caveat: unstable API.

Page 10: Rust tutorial from Boston Meetup 2015-07-22

Open and welcoming

Rust has been open source from the beginning. !

Open governance model based on public RFCs. !

We have an active, amazing community.

10

Page 11: Rust tutorial from Boston Meetup 2015-07-22

Getting Started

11

You can either install Rust, or just use play.rust-lang.org

Exercises are available at: !

http://nikomatsakis.github.io/rust-tutorial-boston-20150722/

Page 12: Rust tutorial from Boston Meetup 2015-07-22

Outline

12

1. The big ideas:!a. Ownership b. Borrowing

2. Everyday life:!a. Data types b. Modules and privacy c. Cargo

Page 13: Rust tutorial from Boston Meetup 2015-07-22

Ownership!!n. The act, state, or right of possessing something.

13

Borrow!!v. To receive something with the promise of returning it.

Page 14: Rust tutorial from Boston Meetup 2015-07-22

The Big Idea

Ownership and borrowing:!!1. All memory has a clear owner. 2. Others can borrow from the owner. 3. Owner cannot free or mutate the

memory while it is borrowed.

14

Page 15: Rust tutorial from Boston Meetup 2015-07-22

Ownership/Borrowing

Memory safety

Data-race freedom

No need for a runtime

GCC++

15

Page 16: Rust tutorial from Boston Meetup 2015-07-22

Clean up the mess

16

http://mylifeandkids.com/messy-house-edition-boys-bedroom-2/

Page 17: Rust tutorial from Boston Meetup 2015-07-22

Ownership17

Page 18: Rust tutorial from Boston Meetup 2015-07-22

fn give() { let mut vec = vec![]; vec.push(1); vec.push(2); take(vec); … }

fn take(vec: Vec<i32>) { // … } !!!

Ownership

Take ownership of a Vec<i32>

18

Page 19: Rust tutorial from Boston Meetup 2015-07-22

fn give() { let mut vec = Vec::new(); vec.push(1); vec.push(2); take(vec); … } vec.push(2);

Compiler enforces moves

fn take(vec: Vec<i32>) { // … } !!!Error: vec has been moved

Prevents: - use after free - double moves - …

19

Page 20: Rust tutorial from Boston Meetup 2015-07-22

void give() { Vector vec = …; vec.add(1); vec.add(2); take(vec); vec.add(3); }

void take(Vector vec) { // … } !!!

“Ownership” in Java

Take reference to Vector

20

Page 21: Rust tutorial from Boston Meetup 2015-07-22

Mutability

21

fn prefix_sum(mut v: Vec<i32>) -> Vec<i32> { let mut sum = 0; for i in 0 .. v.len() { sum += v[i]; v[i] = sum; } v }

http://is.gd/wCtQQZ

1, 2, 3, 4 1, 3, 6, 10

(caller) (prefix sum)

Page 22: Rust tutorial from Boston Meetup 2015-07-22

Clone

22

fn main() { let d = vec![1, 3, 4, 10]; let ps = prefix_sum(d); println!("prefix sum of {:?} is {:?}", d, ps); }

http://is.gd/nbuxdV

Page 23: Rust tutorial from Boston Meetup 2015-07-22

Clone

23

fn main() { let d = vec![1, 3, 4, 10]; let ps = prefix_sum(d.clone()); println!("prefix sum of {:?} is {:?}", d, ps); }

http://is.gd/nbuxdV

1, 2, 3, 4 1, 3, 6, 10(caller) (prefix sum)

1, 2, 3, 4

Page 24: Rust tutorial from Boston Meetup 2015-07-22

24

struct Point { x: u32, y: u32 } !fn area(ul: Point, lr: Point) -> u32 { (lr.x - ul.x) * (lr.y - ul.y) } !fn main() { let origin = Point { x: 0, y: 0 }; let unit = Point { x: 1, y: 1 }; let here = Point { x: 5, y: 6 }; println!(“{:?}”, area(origin, unit)); println!(“{:?}”, area(origin, here)); }

Declare a struct type Point with two

fields, x and y.

// 1// ?

http://is.gd/5dDnaH

32-bit unsigned integer

Page 25: Rust tutorial from Boston Meetup 2015-07-22

“Copy” types

25

#[derive(Copy, Clone)] struct Point { x: u32, y: u32 }

Page 26: Rust tutorial from Boston Meetup 2015-07-22

26

Default: Type cannot be copied. Values move from place to place. Example: File descriptor. !

Clone: Type is expensive to copy, so make it explicit by calling clone(). Example: Vector, hashtable.!!

Copy: Type is implicitly copied whenever it is referenced. Example: u32, i32, Point

Page 27: Rust tutorial from Boston Meetup 2015-07-22

27

Exercise #1.

Page 28: Rust tutorial from Boston Meetup 2015-07-22

* Actually: mutation only in controlled circumstances

*

Shared borrow (&T)

Sharing Mutation

Page 29: Rust tutorial from Boston Meetup 2015-07-22

Mutable borrow (&mut T)29

Sharing Mutation

Page 30: Rust tutorial from Boston Meetup 2015-07-22

30

fn sum(v: Vec<i32>) -> i32 { let mut s = 0; for i in 0 .. v.len() { s += v[i]; } s } !fn main() { let v = vec![1, 2, 3]; println!(“{:?}”, sum(v)); }

Take ownership of a Vec<i32>

Give ownership

Page 31: Rust tutorial from Boston Meetup 2015-07-22

31

fn sum(v: &Vec<i32>) -> i32 { let mut s = 0; for i in 0 .. v.len() { s += v[i]; } s } !fn main() { let v = vec![1, 2, 3]; println!(“{:?}”, sum(&v)); }

Borrow!Vec<i32>

Lend the vectorhttp://is.gd/aHalet

Page 32: Rust tutorial from Boston Meetup 2015-07-22

32

fn prefix_sum(v: &mut Vec<i32>) { let mut s = 0; for i in 0 .. v.len() { s += v[i]; v[i] = s; } } !fn main() { let mut v = vec![1, 2, 3]; prefix_sum(&mut v); println!("{:?}", v); }

Mutable borrow

Mutable loan

http://is.gd/jvKmF2

Page 33: Rust tutorial from Boston Meetup 2015-07-22

fn example() { let mut names = Vec::new(); names.push(..); names.push(..); let name = &names[1]; names.push(..); print(name); }

names

data

length

capacity

“brson”

“pcwalton”

name

“brson”

“pcwalton”

“acrichto”

Sharing: more than one pointer to same memory.

Dangling pointer: pointer to freed memory.

Mutating the vector freed old contents.

33

Page 34: Rust tutorial from Boston Meetup 2015-07-22

Rust solution

34

Compile-time read-write-lock:!!Creating a shared reference to X “read locks” X. - Other readers OK. - No writers. - Lock lasts until reference goes out of scope. !Creating a mutable reference to X “writes locks” X. - No other readers or writers. - Lock lasts until reference goes out of scope.

Never have a reader/writer at same time.

Page 35: Rust tutorial from Boston Meetup 2015-07-22

fn example() { let mut names = Vec::new(); names.push(“brson”); names.push(“pcwalton”); let name = &names[1]; names.push(“acrichto”); println!(“{:?}”, name); }

Borrow “locks” `names` until `name` goes out of scopeError: cannot mutate

`names` while borrowed

35http://is.gd/jeKW1E

Page 36: Rust tutorial from Boston Meetup 2015-07-22

Outside of borrow scope — OK.

Scope of borrow in this case covers only the loop body.

36http://is.gd/thMY5N

fn main() { let mut names = Vec::new(); names.push("brson"); names.push("pcwalton"); for i in 0 .. names.len() { let name = &names[i]; names.push("acrichto"); println!("{:?}", name); } names.push("acrichto"); }

Page 37: Rust tutorial from Boston Meetup 2015-07-22

Rust reasons about scopes

37

fn main() { let mut names = Vec::new(); names.push("brson"); names.push("pcwalton"); for i in 0 .. names.len() { let name = &names[i]; println!("{:?}", name); names.push("acrichto"); } names.push("acrichto"); }

Even though reference is not used, it is still in scope for the entire block..

http://is.gd/pLE8bb

Page 38: Rust tutorial from Boston Meetup 2015-07-22

Take a break.

38

Page 39: Rust tutorial from Boston Meetup 2015-07-22

Daily life in Rust

39

Page 40: Rust tutorial from Boston Meetup 2015-07-22

Methods

40

struct Point { x: f32, y: f32, } !impl Point { fn new() -> Point { Point { x: 0.0, y: 0.0 } } ! fn negate(&self) -> Point { Point { x: -self.x, y: -self.y } } }

http://is.gd/KbbORT

Page 41: Rust tutorial from Boston Meetup 2015-07-22

Common derivations

41

#[derive(PartialEq)]

+ #[derive(PartialOrd)]

#[derive(Clone)]

#[derive(Debug)]

x == y, x != y

x < y, x <= y, …

x.clone()

+ #[derive(Copy)] use(x); use(x);

println!(“{:?}”, x);

#[derive(Hash)] HashMap<T>

Page 42: Rust tutorial from Boston Meetup 2015-07-22

Enums

42

struct Point {..} !enum Shape { Circle { origin: Point, radius: f32 }, ! Rectangle { ul: Point, lr: Point } }

Page 43: Rust tutorial from Boston Meetup 2015-07-22

43

struct Point {..} !enum Shape { Circle { origin: Point, radius: f32 }, Rectangle { ul: Point, lr: Point } } !impl Shape { fn unit_circle() -> Shape { Shape::Circle { origin: Point { x: 0.0, y: 0.0 }, radius: 1.0 } } }

Page 44: Rust tutorial from Boston Meetup 2015-07-22

const PI: f32 = 3.14159; impl Shape { fn area(&self) -> f32 { match *self { Shape::Circle { origin: _, radius: r } => PI * r * r, ! Shape::Rectangle { ul, lr } => (lr.y - ul.y).abs() * (lr.x - ul.x).abs() } } }

44http://is.gd/a2YcvG

Page 45: Rust tutorial from Boston Meetup 2015-07-22

Option

45

enum Option<T> { None, Some(T), }

Page 46: Rust tutorial from Boston Meetup 2015-07-22

No null types

46

class Shape { Color color; ! Shape() { } ! Color getColor(Color default) { if (color != null) return color; return default; } }

(Java)

Page 47: Rust tutorial from Boston Meetup 2015-07-22

47

struct Shape { color: Option<Color> } !impl Shape { fn new() -> Shape { Shape { color: None } } ! fn get_color(&self, default: Color) -> Color { match self.color { None => default, Some(ref c) => c.clone() } } } (Rust)

Page 48: Rust tutorial from Boston Meetup 2015-07-22

48

match self.color { None => default, Some(ref c) => c.clone() }

if let Some(ref c) = self.color { c.clone() } else { default }

self.color.unwrap_or(default)

self.color.unwrap_or_else(|| default)

Page 49: Rust tutorial from Boston Meetup 2015-07-22

Slices

49

fn main() { // Heap-allocated. let v: Vec<i32> = vec![1, 2, 3, 4]; ! // Reference to one element. let e: &i32 = &v[1]; ! // Reference to many elements. let slice: &[i32] = &v[1..3]; }

http://is.gd/QftPT8

Page 50: Rust tutorial from Boston Meetup 2015-07-22

Mutable slices

50

fn main() { // Heap-allocated. let mut v: Vec<i32> = vec![1, 2, 3, 4]; println!(“v={:?}”, v); { let slice = &mut v[..]; slice[1] += 22; } println!(“v={:?}”, v); }

http://is.gd/31rKv5

Page 51: Rust tutorial from Boston Meetup 2015-07-22

For loops and slices

51

for x in &v { // x is an &i32 }

let v: Vec<i32> = vec![1, 2, 3, 4];

for x in &mut v { // x is an &mut i32 }

for x in v { // x is an i32 } // v is consumed after loop

for converts its argument into an iterator using the IntoIterator trait

Page 52: Rust tutorial from Boston Meetup 2015-07-22

Iterators

52

struct PlayerScore { player_name: String, score: u32 } !fn high_scorers(v: Vec<PlayerScore>) -> Vec<(String, u32)> { v.into_iter() .filter(|ps| ps.score > 20) .map(|ps| (ps.player_name, ps.score)) .collect() }

Page 53: Rust tutorial from Boston Meetup 2015-07-22

Programming in the large

53

Page 54: Rust tutorial from Boston Meetup 2015-07-22

Cargo

54

> cargo new my_project > cargo new —-bin my_project

> cd my_project > emacs

Create a template for a new project:

Edit your project:

> cargo build [—-release] > cargo test

Build and test your project:

http://doc.crates.io/guide.html

Page 55: Rust tutorial from Boston Meetup 2015-07-22

Dependencies

55

[package] name = "hello_world" version = "0.1.0" authors = ["Your Name <[email protected]>”] ![dependencies] regex = "0.1.41"

Cargo.toml

lib.rs

extern crate regex;

Page 56: Rust tutorial from Boston Meetup 2015-07-22

Modules

56

mod data; mod code;

lib.rs/main.rs

data/mod.rs

mod point; mod shape;

data/point.rs

struct Point { }

:: data point shape code

data/shape/mod.rs

struct Point { }

Page 57: Rust tutorial from Boston Meetup 2015-07-22

Often used to make a mod test for unit tests, or for demonstations.

Inline modules

57

mod data { mod point { .. } ! mod shape { .. } } !mod code {

lib.rs/main.rs Exactly the same as creating a separate file.

Page 58: Rust tutorial from Boston Meetup 2015-07-22

Use

58

:: data point shape code

code.rs

use data::point::Point;

data/mod.rs

use data::point::Point; use self::point::Point;

data/shape.rs

use data::point::Point; use super::point::Point;

Page 59: Rust tutorial from Boston Meetup 2015-07-22

Privacy

59

Privacy is the default, use pub to override.

pub struct Point { pub x: f32, pub y: f32, }

impl Point { pub fn m(&self); }

pub enum Shape { … }

pub mod child;

Private means: code in this module or a descendant.

Page 60: Rust tutorial from Boston Meetup 2015-07-22

Where to learn more

60

doc.rust-lang.org/book

users.rust-lang.org / IRC / Stackoverflow

doc.rust-lang.org/std

Page 61: Rust tutorial from Boston Meetup 2015-07-22

61

Thanks for

listenin

g!