Rust tutorial from Boston Meetup 2015-07-22
-
Upload
nikomatsakis -
Category
Software
-
view
594 -
download
3
Transcript of 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 :)
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.
// 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.
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
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.
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.
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.
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
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/
Outline
12
1. The big ideas:!a. Ownership b. Borrowing
2. Everyday life:!a. Data types b. Modules and privacy c. Cargo
Ownership!!n. The act, state, or right of possessing something.
13
Borrow!!v. To receive something with the promise of returning it.
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
Clean up the mess
16
http://mylifeandkids.com/messy-house-edition-boys-bedroom-2/
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
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
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
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)
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
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
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
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
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
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
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
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
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.
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
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"); }
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
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
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>
Enums
42
struct Point {..} !enum Shape { Circle { origin: Point, radius: f32 }, ! Rectangle { ul: Point, lr: Point } }
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 } } }
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
No null types
46
class Shape { Color color; ! Shape() { } ! Color getColor(Color default) { if (color != null) return color; return default; } }
(Java)
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)
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)
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
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
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
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() }
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
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;
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 { }
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.
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;
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.
Where to learn more
60
doc.rust-lang.org/book
users.rust-lang.org / IRC / Stackoverflow
doc.rust-lang.org/std