Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hello, Rust! — An overview

Hello, Rust! — An overview

This talk is an overview of the Rust language. It has been presented during http://www.agendadulibre.org/events/12769. Not all slides have been detailed. The goal of this meetup was to have an overview of the Rust language, and to talk about what the public was curious about.

A live-coding/live-contribution session has also been organized at the end: Take a real project from the audience, see how to enhance it, how to be more idiomatic, better memory management, better data design etc.

Ivan Enderlin

February 02, 2017
Tweet

More Decks by Ivan Enderlin

Other Decks in Programming

Transcript

  1. Disclaimer • I am not an expert • “Rust is

    good at x” ⇏ “other languages are n00bs” • Not exhaustive, this is an overview!
  2. History • Father Graydon Hoare (thanks!) • Officially born in

    2009, announced in 2010 • 1.0 release the 15th of May 2015 • Sponsored by Mozilla Research
  3. Why Rust? • Low-level with no fear • Safety guarantees

    • Type system (algebraic types, associated types, kinds, inference, affine…) • Traits • Concurrency • Extremely fast • FFI • No garbage collector • Error handling • Community & documentation • Cross platform
  4. Mutability • Everything is immutable by default • mut to

    make a data mutable let x = 7; x = 42;
  5. Mutability • Everything is immutable by default • mut to

    make a data mutable error[E0384]: re-assignment of immutable variable `x` let x = 7; x = 42;
  6. Mutability • Everything is immutable by default • mut to

    make a data mutable let mut x = 7; x = 42; println!("x = {}", x);
  7. Mutability • Everything is immutable by default • mut to

    make a data mutable let mut x = 7; x = 42; println!("x = {}", x); x = 42
  8. Ownership • Variable bindings (let) have a property in Rust:

    they “have ownership” of what they are bound to • When a binding goes out of scope, Rust will free the bound resources • This happens deterministically, at the end of the scope
  9. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … }
  10. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … } Rust The ultimate book
  11. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … } Rust The ultimate book
  12. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … } Rust The ultimate book
  13. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … } Rust The ultimate book
  14. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … } Rust The ultimate book
  15. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … }
  16. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … }
  17. Ownership The move semantics fn main() { let book =

    Book { /* … */ }; read_book(book); read_book(book); } fn read_book(book: Book) { // … } error[E0382]: use of moved value: `book`
  18. Ownership Retrieve the book fn read_book(book: Book) -> Book {

    // … book } Solution 1 Return the data Solution 2 Clone book before passing it to read_book Solution 3 Share it!
  19. Borrowing • We call the &T type a “reference” •

    Rather than owning the resource, a binding borrows ownership • A binding that borrows something does not deallocate the resource when it goes out of scope • A borrowed resource is immutable
  20. fn main() { let book = Book { /* …

    */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference fn read_book(book: &Book) { // … }
  21. Rust The ultimate book Rust The ultimate book fn main()

    { let book = Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  22. Rust The ultimate book Rust The ultimate book fn main()

    { let book = Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  23. Rust The ultimate book Rust The ultimate book fn main()

    { let book = Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  24. Rust The ultimate book Rust The ultimate book fn main()

    { let book = Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  25. Rust The ultimate book Rust The ultimate book fn main()

    { let book = Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  26. Rust The ultimate book fn main() { let book =

    Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  27. Rust The ultimate book fn main() { let book =

    Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  28. Rust The ultimate book fn main() { let book =

    Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  29. Rust The ultimate book fn main() { let book =

    Book { /* … */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  30. fn main() { let book = Book { /* …

    */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  31. fn main() { let book = Book { /* …

    */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference Rust The ultimate book fn read_book(book: &Book) { // … }
  32. fn main() { let book = Book { /* …

    */ }; read_book(&book); read_book(&book); } Borrowing &T is a reference fn read_book(book: &Book) { // … }
  33. Borrowing &mut T is a mutable reference fn read_book(book: &mut

    Book) { book.name = String::from("bar"); } fn main() { let mut book = Book { name: String::from("foo") }; read_book(&mut book); println!("Book name is {}", book.name); }
  34. Borrowing &mut T is a mutable reference fn read_book(book: &mut

    Book) { book.name = String::from("bar"); } fn main() { let mut book = Book { name: String::from("foo") }; read_book(&mut book); println!("Book name is {}", book.name); }
  35. Borrowing &mut T is a mutable reference fn read_book(book: &mut

    Book) { book.name = String::from("bar"); } fn main() { let mut book = Book { name: String::from("foo") }; read_book(&mut book); println!("Book name is {}", book.name); }
  36. Borrowing &mut T is a mutable reference fn read_book(book: &mut

    Book) { book.name = String::from("bar"); } fn main() { let mut book = Book { name: String::from("foo") }; read_book(&mut book); println!("Book name is {}", book.name); }
  37. Borrowing &mut T is a mutable reference fn read_book(book: &mut

    Book) { book.name = String::from("bar"); } fn main() { let mut book = Book { name: String::from("foo") }; read_book(&mut book); println!("Book name is {}", book.name); } Book name is bar
  38. The rules Type Mutable Number of sharings T ❌ Zero

    &T ❌ One or more &mut T ✅ Exactly one
  39. The rules Type Mutable Number of sharings T ❌ Zero

    &T ❌ One or more &mut T ✅ Exactly one i.e. many readers, one writer
  40. Lifetimes • Each reference has a lifetime • Prevent dangling

    pointer, aka use after free • Let the following scenario: • I have a data, • I send you a reference to this data, • I am done with it, and I deallocate it, while you still have the reference, • You use this data, and .
  41. Lifetimes let x; // Introduce `x` { let y =

    7; // Introduce scoped value `y` x = &y; // Store reference of `y` in `x` } // `y` goes out of scope and is dropped println!("{}", x); // `x` still refers to `y`
  42. Lifetimes let x; // Introduce `x` { let y =

    7; // Introduce scoped value `y` x = &y; // Store reference of `y` in `x` } // `y` goes out of scope and is dropped println!("{}", x); // `x` still refers to `y` error: `y` does not live long enough | 4 | x = &y; | - borrow occurs here 5 | } | ^ `y` dropped here while still borrowed ... 8 | } | - borrowed value needs to live until here
  43. Lifetime elision • Function body: Lifetime is always inferred •

    Function I/O: Lifetime can be ambiguous, so annotation might be required
  44. Lifetimes fn f(x: &str, y: &str) -> &str { x

    } fn main() { let x = "foo"; let z; { let y = "bar"; z = f(x, y); } println!("z = {}", z); }
  45. Lifetimes fn f(x: &str, y: &str) -> &str { x

    } fn main() { let x = "foo"; let z; { let y = "bar"; z = f(x, y); } println!("z = {}", z); } ^ expected lifetime parameter error[E0106]: missing lifetime specifier
  46. Lifetimes fn f<'a, 'b>(x: &'a str, y: &'b str) ->

    &'a str { x } fn main() { let x = "foo"; let z; { let y = "bar"; z = f(x, y); } println!("z = {}", z); } • 'a means lifetime a • &'a means the reference has lifetime a • f<'a, 'b> means f has 2 explicit lifetimes
  47. Lifetimes fn f<'a, 'b>(x: &'a str, y: &'b str) ->

    &'a str { y } error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> <anon>:2:5 | 2 | y | ^ | note: ...the reference is valid for the lifetime 'a as defined on the block at 1:48... --> <anon>:1:49 | 1 | fn f<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { | ^ note: ...but the borrowed content is only valid for the lifetime 'b as defined on the block at 1:48 --> <anon>:1:49 | 1 | fn f<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { | ^ help: consider using an explicit lifetime parameter as shown: fn f<'a>(x: &'a str, y: &'a str) -> &'a str --> <anon>:1:1 | 1 | fn f<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { | ^
  48. Algebraic types • Types are inferred • What algebra means?

    • ربجلا = reunion (of broken parts) ✓ Reunion of types • Elementary algebra includes arithmetic operations, like ⨉ and +
  49. Product types • S = T1 ⨉ T2 ⨉ …

    ⨉ Ti ⨉ … ⨉ Tm where Ti is a type ‣ S = T1 ⋀ T2 ⋀ … ⋀ Ti ⋀ … ⋀ Tm • S is called a product type • Ti is called an operand of S • Size of a value v: S is the sum of the size of all Ti
  50. Sum types • E = T1 + T2 + …

    + Ti + … + Tm where Ti is a type ‣ E = T1 ⋁ T2 ⋁ … ⋁ Ti ⋁ … ⋁ Tm • E is called a sum type, or a tagged union • Ti is called a variant of E • A value v: E has one type Ti represented by a tag
  51. Units • Unit type is a degenerated form of a

    product type • Product of no type: No name and no operands () • Construct let unit = ();
  52. Tuples • Product type with no name and indexed operands

    (i32, i32, i32) • Construct let point = (7, 42, 153); • Read let x = point.0; let (x, _, z) = point;
  53. Tuple structures • Product type with a name and indexed

    operands struct Point(i32, i32, i32) • Construct let point = Point(7, 42, 153); • Read let Point(x, y, z) = point;
  54. Structures • Product type with a name and named operands

    struct Point { x: i32, y: i32, z: i32 } • Construct let point = Point { x: 7, y: 42, z: 153 }; • Read let x = point.x; let Point { x, .. } = point;
  55. Unit-like structures • Product type with a name and no

    operands struct Point { } struct Point • Construct let point = Point { }; let point = Point;
  56. Enumerators • Sum type with one or more variants •

    Each variant can be of any type (tuple, structure…) enum Message { Quit, ChangeColor(i32, i32, i32, i32), Move { x: i32, y: i32, z: i32 }, Private(String), Public(String) }
  57. Enumerators • Construct let message = Message::Move { x: 7,

    y: 42, z: 153 }; • Read let Message::Move { x, y, z } = message;
  58. Pattern matching • match is like if/else with super powers

    • Can benefit from all types • If not exhaustive, compiler will yell • e.g. a variant of an enumerator is missing • i.e. not tested
  59. Pattern matching Single patterns let x = 3; let number

    = match x { 1 => "one", 2 => "two", 3 => "three", 4 => "four", 5 => "five", _ => "something else" };
  60. Pattern matching Multiple patterns let x = 3; match x

    { 1 | 2 | 3 => println!("one or two or three"), 4 => println!("four"), 5 | 6 | 7 => println!("five or six or seven"), _ => println!("anything") }
  61. Pattern matching Ranges let x = 7; match x {

    1 ... 3 => println!("one or two or three"), 4 => println!("four"), 5 ... 7 => println!("five or six or seven"), _ => println!("anything") }
  62. Pattern matching Bindings let x = 5; match x {

    e @ 1 ... 3 | e @ 5 ... 7 => println!("got {}", e), _ => println!("anything"), }
  63. Pattern matching Destructuring match message { Message::Quit => println!("Bye bye!"),

    Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") }
  64. Pattern matching Destructuring let message = Message::Quit; match message {

    Message::Quit => println!("Bye bye!"), Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") }
  65. Pattern matching Destructuring let message = Message::Quit; match message {

    Message::Quit => println!("Bye bye!"), Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") } Bye bye!
  66. Pattern matching Destructuring match message { Message::Quit => println!("Bye bye!"),

    Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") } let message = Message::Public(String::from("hello"));
  67. Pattern matching Destructuring match message { Message::Quit => println!("Bye bye!"),

    Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") } let message = Message::Public(String::from("hello")); “hello”
  68. Pattern matching Destructuring match message { Message::Quit => println!("Bye bye!"),

    Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") } let message = Message::Move { x: 7, y: 42, z: 153 };
  69. Pattern matching Destructuring match message { Message::Quit => println!("Bye bye!"),

    Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") } let message = Message::Move { x: 7, y: 42, z: 153 }; Move to (7, 42)
  70. Pattern matching Destructuring match message { Message::Quit => println!("Bye bye!"),

    Message::Public(message) => println!("“{}”", message), Message::Move { x, y, .. } => println!("Move to ({}, {})", x, y), _ => println!("Oops…") }
  71. Pattern matching Guards enum OptionalInt { Value(i32), MissingValue, } let

    x = OptionalInt::Value(5); match x { OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than 5!"), OptionalInt::Value(..) => println!("Got an int!"), OptionalInt::Missing => println!("No such luck.") }
  72. Methods • Methods are functions bounded to a type •

    Structures • Enumerators • Primitives
  73. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  74. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  75. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  76. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  77. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  78. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  79. Methods struct Circle { x : f64, y : f64,

    radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); }
  80. Methods • First parameter is special: self • self if

    it's a value on the stack, take ownership • &self if it's a reference • &mut self if it's a mutable reference • What if no self provided?
  81. Associated functions impl Circle { fn new(x: f64, y: f64,

    radius: f64) -> Circle { Circle { x : x, y : y, radius: radius } } fn area(&self) -> f64 { … } } fn main() { let c = Circle::new(0.0, 0.0, 2.0); println!("{}", c.area()); }
  82. Associated functions impl Circle { fn new(x: f64, y: f64,

    radius: f64) -> Circle { Circle { x : x, y : y, radius: radius } } fn area(&self) -> f64 { … } } fn main() { let c = Circle::new(0.0, 0.0, 2.0); println!("{}", c.area()); }
  83. Associated functions impl Circle { fn new(x: f64, y: f64,

    radius: f64) -> Circle { Circle { x : x, y : y, radius: radius } } fn area(&self) -> f64 { … } } fn main() { let c = Circle::new(0.0, 0.0, 2.0); println!("{}", c.area()); }
  84. Parametric polymorphism • Also known as Generic • Many (poly)

    forms (morph) • Static dispatch by default (monomorphization) • Dynamic dispatch for trait objects (not detailed, see doc)
  85. Parametric polymorphism Generic functions fn takes_anything<T>(x: T) { // …

    } takes_anything(7u8); takes_anything(4.2f32); fn takes_anything_u8(x: u8) { // … } fn takes_anything_f32(x: f32) { // … } takes_anything_u8(7u8); takes_anything_f32(4.2f32);
  86. Parametric polymorphism Generic functions fn takes_anything<T>(x: T) { // …

    } takes_anything(7u8); takes_anything(4.2f32); fn takes_anything_u8(x: u8) { // … } fn takes_anything_f32(x: f32) { // … } takes_anything_u8(7u8); takes_anything_f32(4.2f32); Statically dispatched by the compiler
  87. Parametric polymorphism Generic structures struct Point<T> { x: T, y:

    T } let int_origin = Point { x: 0, y: 0 }; let float_origin = Point { x: 0.0, y: 0.0 };
  88. Parametric polymorphism Generic enumerators enum Foo<T> { Bar, Baz(T), Qux

    { z: T } } let int_baz = Foo::Baz(0); let float_baz = Foo::Baz(0.0);
  89. Option • null does not exist in Rust • Option

    to represent an optional value enum Option<T> { Some(T), None } let x = Some(7); let y = None;
  90. Result • No exception in Rust • Result is the

    error handling mechanism enum Result<T, E> { Ok(T), Err(E) } let x = Ok(7); let y = Err("Too bad");
  91. Traits • Object, interface, type capability… all mixed • Tells

    the compiler about functionality a type must provide • Can be implemented on any types (structures, enumerators, primitive types) • This is where things becomes very interesting and delicious
  92. Traits struct Circle { x : f64, y : f64,

    radius: f64 } trait HasArea { fn area(&self) -> f64; } impl HasArea for Circle { fn area(&self) -> f64 { … } }
  93. Traits struct Circle { x : f64, y : f64,

    radius: f64 } trait HasArea { fn area(&self) -> f64; } impl HasArea for Circle { fn area(&self) -> f64 { … } }
  94. Traits struct Circle { x : f64, y : f64,

    radius: f64 } trait HasArea { fn area(&self) -> f64; } impl HasArea for Circle { fn area(&self) -> f64 { … } }
  95. Traits struct Circle { x : f64, y : f64,

    radius: f64 } trait HasArea { fn area(&self) -> f64; } impl HasArea for Circle { fn area(&self) -> f64 { … } }
  96. Traits Bound on generic functions fn print_area<T: HasArea>(shape: T) {

    println!("This shape has an area of {}", shape.area()); }
  97. Traits Bound on generic functions fn print_area<T: HasArea>(shape: T) {

    println!("This shape has an area of {}", shape.area()); } T: HasArea means type T implements the HasArea trait
  98. Traits Bound on generic functions fn print_area<T: HasArea>(shape: T) {

    println!("This shape has an area of {}", shape.area()); } T: HasArea means type T implements the HasArea trait Monomorphization applies, i.e. statically dispatched
  99. Traits Multiple bounds on generic functions fn print_area<T: HasName +

    HasArea>(shape: T) { println!("{} has an area of {}", shape.name(), shape.area()); }
  100. Traits Multiple bounds on generic functions fn print_area<T: HasName +

    HasArea>(shape: T) { println!("{} has an area of {}", shape.name(), shape.area()); } + represents a list of traits
  101. Traits where clause fn print_area<T>(shape: T) where T: HasName +

    HasArea { println!("{} has an area of {}", shape.name(), shape.area()); }
  102. Traits where clause fn print_area<T>(shape: T) where T: HasName +

    HasArea { println!("{} has an area of {}", shape.name(), shape.area()); } where allows to express traits on type, just like before More powerful syntax, not detailed here
  103. Traits Default methods trait Foo { fn is_valid(&self) -> bool;

    fn is_invalid(&self) -> bool { !self.is_valid() } } Can be overridden
  104. RAII • Resource Acquisition Is Initialisation • No manual allocation,

    no manual deallocation, no garbage collector • The Drop trait is used to run some code when a value goes out of scope • Default implementations for particular types (Rc, Weak, Arc…)
  105. Drop struct Firework { strength: i32 } impl Drop for

    Firework { fn drop(&mut self) { println!("BOOM times {}!", self.strength); } } fn main() { let firecracker = Firework { strength: 1 }; let tnt = Firework { strength: 100 }; }
  106. Drop struct Firework { strength: i32 } impl Drop for

    Firework { fn drop(&mut self) { println!("BOOM times {}!", self.strength); } } fn main() { let firecracker = Firework { strength: 1 }; let tnt = Firework { strength: 100 }; } BOOM times 100!
  107. Drop struct Firework { strength: i32 } impl Drop for

    Firework { fn drop(&mut self) { println!("BOOM times {}!", self.strength); } } fn main() { let firecracker = Firework { strength: 1 }; let tnt = Firework { strength: 100 }; } BOOM times 1!
  108. Drop struct Firework { strength: i32 } impl Drop for

    Firework { fn drop(&mut self) { println!("BOOM times {}!", self.strength); } } fn main() { let firecracker = Firework { strength: 1 }; let tnt = Firework { strength: 100 }; } BOOM times 1! First in, last out
  109. Stack & Heap • Everything is allocated on the stack

    by default • Fast • Scoped to the function • Limited in size • To allocate on the heap, use Box
  110. Slices • A dynamically-sized view into a contiguous sequence [T]

    • A slice is a subset of a collection struct Slice<T> { data : *const T, length: usize } • Work on subsets with no fear and no copy • All Rust guarantees apply!
  111. Unsafety • Some programs are safe but cannot be verified

    by the compiler • unsafe keyword only allows three things: 1. Access or update a static mutable variable 2. Dereference a raw pointer 3. Call unsafe functions (the most powerful ability) • Does not turn off the borrow checker or other guarantees • See documentation for more details
  112. Iterators • Rust as its best • High-level constructions •

    Short and efficient low-level results • Strong safety guarantees • Producers and consumers model
  113. Iterators Basic example let a = [1, 2, 3]; let

    iterator = a.into_iter().map(|x| 2 * x); for i in iterator { println!("{}", i); } 2 4 6
  114. Iterators Basic example, unfolded let a = [1, 2, 3];

    let mut iterator = a.into_iter().map(|x| 2 * x); while let Some(i) = iterator.next() { println!("{}", i); }
  115. Iterators Basic example, unfolded let a = [1, 2, 3];

    let mut iterator = a.into_iter().map(|x| 2 * x); while let Some(i) = iterator.next() { println!("{}", i); } Producer
  116. Iterators Basic example, unfolded let a = [1, 2, 3];

    let mut iterator = a.into_iter().map(|x| 2 * x); while let Some(i) = iterator.next() { println!("{}", i); } Consumer
  117. Iterators Producers & consumers explained let a = [1u32, 2,

    3, 4, 6, 7, 8]; let sum: u32 = a.into_iter() .filter(|&x| x % 2 == 0) .map(|x| x * 2) .sum(); println!("sum is {}", sum);
  118. Iterators Producers & consumers explained let a = [1u32, 2,

    3, 4, 6, 7, 8]; let sum: u32 = a.into_iter() .filter(|&x| x % 2 == 0) .map(|x| x * 2) .sum(); println!("sum is {}", sum); Create an iterator
  119. Iterators Producers & consumers explained let a = [1u32, 2,

    3, 4, 6, 7, 8]; let sum: u32 = a.into_iter() .filter(|&x| x % 2 == 0) .map(|x| x * 2) .sum(); println!("sum is {}", sum); Producer: Filter results (note the &x)
  120. Iterators Producers & consumers explained let a = [1u32, 2,

    3, 4, 6, 7, 8]; let sum: u32 = a.into_iter() .filter(|&x| x % 2 == 0) .map(|x| x * 2) .sum(); println!("sum is {}", sum); Producer: Map results (note the x)
  121. Iterators Producers & consumers explained let a = [1u32, 2,

    3, 4, 6, 7, 8]; let sum: u32 = a.into_iter() .filter(|&x| x % 2 == 0) .map(|x| x * 2) .sum(); println!("sum is {}", sum); Consumer: Collect by summing results
  122. Iterators Producers & consumers explained let a = [1u32, 2,

    3, 4, 6, 7, 8]; let sum: u32 = a.into_iter() .filter(|&x| x % 2 == 0) .map(|x| x * 2) .sum(); println!("sum is {}", sum); sum is 40
  123. Concurrency & parallelism • Hard & long, but incredibly important

    topics • Voluntarily small but powerful API in std • Two traits & the borrow checker to ensure safety • Several libraries to go further
  124. Send & Sync • When a type T implements Send,

    it indicates that something of this type is able to have ownership transferred safely between threads • When a type T implements Sync, it indicates that something of this type has no possibility of introducing memory unsafety when used from multiple threads concurrently through shared references
  125. Thread Return a value use std::thread; fn main() { let

    handle = thread::spawn(|| { "Hello from a thread!" }); println!("{}", handle.join().unwrap()); }
  126. Thread Closure, references & move semantics fn main() { let

    x = 1; thread::spawn(|| { println!("x is {}", x); }); }
  127. Thread Closure, references & move semantics fn main() { let

    x = 1; thread::spawn(|| { println!("x is {}", x); }); } 5:19: 7:6 error: closure may outlive the current function, but it borrows `x`, which is owned by the current function ... 5:19: 7:6 help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword, as shown: thread::spawn(move || { println!("x is {}", x); });
  128. Thread Closure, references & move semantics 5:19: 7:6 error: closure

    may outlive the current function, but it borrows `x`, which is owned by the current function ... 5:19: 7:6 help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword, as shown: thread::spawn(move || { println!("x is {}", x); }); fn main() { let x = 1; thread::spawn(move || { println!("x is {}", x); }); }
  129. –Someone “Shared mutable state is the root of all evil.

    Most languages attempt to deal with this problem through the ‘mutable’ part, but Rust deals with it by solving the ‘shared’ part.”
  130. Thread Safe Shared Mutable State • Rc, a single-threaded reference-counting

    pointer, immutable, no Send or Sync • Cell or RefCell to get immutability • Arc, a thread-safe (atomic) reference-counting pointer, immutable, with Send and Sync • Mutex or RwLock (or more) to get mutability • more…
  131. Thread Balance • Some constraints can be checked at compile-time

    with the borrow checker, traits etc. • Some constraints are checked at runtime • My advices 1. Check if a crate already exists 2. Check “big projects”, e.g. Servo or Redox
  132. –Edsger W. Dijkstra, "The Humble Programmer" (1972) “Program testing can

    be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence”
  133. Tests • Rust hardly tries to ensure a high quality

    ecosystem • Simple but efficient mechanisms to write and run tests • cargo test to run them all
  134. Tests Unit and integration suites #[test] fn case_foo() { let

    input = …; let output = …; assert_eq!(sut(input), output); } $ cargo run --lib
  135. Tests Documentation /// Short description. /// /// Detailed description. ///

    /// # Examples /// /// ``` /// struct S { x: u32, y: u32 } /// # fn main() { /// let input = S { x: 7, y: 42 }; /// let output = …; /// /// assert_eq!(sut(input), output); /// ); /// # } /// ``` fn sut(s: S) -> t { … }
  136. Tests Documentation /// Short description. /// /// Detailed description. ///

    /// # Examples /// /// ``` /// struct S { x: u32, y: u32 } /// # fn main() { /// let input = S { x: 7, y: 42 }; /// let output = …; /// /// assert_eq!(sut(input), output); /// ); /// # } /// ``` fn sut(s: S) -> t { … }
  137. Tests Documentation /// Short description. /// /// Detailed description. ///

    /// # Examples /// /// ``` /// struct S { x: u32, y: u32 } /// # fn main() { /// let input = S { x: 7, y: 42 }; /// let output = …; /// /// assert_eq!(sut(input), output); /// ); /// # } /// ``` fn sut(s: S) -> t { … } • cargo test --doc • compile and run each examples as a standalone program • cargo doc • compile the documentation into HTML
  138. Compiler • Self-hosted compiler (Rust is written in Rust) •

    New release every 6 weeks • Different channels: stable, beta, nightly • LLVM for the backend • Lot of target triples supported • Including WebAssembly (experimental)
  139. Crate • Can be a binary • Can be a

    library of type • lib (ambiguous) • dylib (.so, .dylib, .dll) • rlib (Rust static lib) • staticlib (.a, .lib) • cdylib (.so, .dylib, .dll) • proc-macro (procedural macros)
  140. rustup • Toolchain installer curl https://sh.rustup.rs -sSf | sh •

    Update rustup update • Easy cross-compilation rustup target add arm-linux-androideabi
  141. cargo • build • clean • doc • new •

    init • run • test • bench • install • … • Official package manager • Repository on crates.io • Invoke rustc for you
  142. xargo • Sysroot manager to build and customise std •

    Cross compile Rust crates for targets that don't have binary releases of the standard crates cargo install xargo xargo build … • CLI is exactly like cargo
  143. Documentations • Book, https://doc.rust-lang.org/book/ • FAQ, https://www.rust-lang.org/en-US/faq.html • rustc --explain

    • std, https://doc.rust-lang.org/std/ • Rust by example, http://rustbyexample.com/ • into_rust(), http://intorust.com/
  144. Gardens • Forum, https://users.rust-lang.org • Reddit, https://reddit.com/r/rust • IRC, irc://irc.mozilla.org#rust

    • YouTube, https://www.youtube.com/channel/UC… • Twitter, https://twitter.com/rustlang
  145. Servo • https://servo.org/ • The Parallel Browser Engine Project •

    Stylo • Constellation • WebRender • … • Being integrated in Firefox (project Quantum)
  146. Redox • https://redox-os.org/ • Unix-like Operating System written in Rust

    • kernel • orbital • tfs • ralloc • ion
  147. ralloc • https://github.com/redox-os/ralloc • A fast & memory efficient userspace

    allocator • Thread-local allocation • First-class debugger support • Logging • Custom out-of-memory handlers • Thread-specific OOM handlers • Partial deallocation • Platform agnostic • Safe SBRK • Useless alignments • Top notch security • …
  148. Mio & Tokio • https://tokio.rs/ • Metal I/O • A

    platform for writing fast networking code with Rust • Futures • Core • Proto(col) • Service
  149. Rayon • https://github.com/nikomatsakis/rayon/ • A data parallelism library for Rust

    • s/.iter()/.par_iter()/g, tadaa fn sum_of_squares(input: &[i32]) -> i32 { input.par_iter() .map(|&i| i * i) .sum() }
  150. Web, ORM, HTTP • http://arewewebyet.org • http://ironframework.io/ • Extensible, concurrent

    web framework • http://diesel.rs/ • Safe, extensible ORM and query builder • https://hyper.rs/ • Low-level typesafe abstraction over raw HTTP • Provides an elegant layer over "stringly-typed" HTTP
  151. • http://www.piston.rs/ • A modular open source game engine •

    Image • Music • Conrod, 2D GUI library • Gfx • Sprite • …
  152. nom • https://github.com/Geal/nom/ • Rust parser combinator framework • Byte-,

    bit-, string-oriented • Zero-copy • Streaming • Macro based syntax • State machine handling • Descriptive errors • Custom error types • Safe parsing • Fast • …
  153. Writing an OS in Rust • http://os.phil-opp.com/ • A series

    of articles explaining how to write an OS in Rust • Very interesting and instructive!
  154. Tagua VM • http://tagua.io/ • An experimental PHP Virtual Machine

    • Several libraries • Parser • Passes/analysis • Idiomatic LLVM bindings • Virtual Machine • All extensions • …
  155. et cætera • It was just an overview • Tons

    of interesting ideas and projects • Nothing new in Rust, just 40 years of research finally in a single efficient & productive language • RustBelt, Formally verify several Rust safety properties, http://plv.mpi- sws.org/rustbelt/
  156. Sources for this talk • Rust Book and various documentations

    • Blog posts • My experience and understanding • I have learned a lot, and I still have a lot to learn
  157. Q&A Thank you ❤ Ask me anything https://www.rust-lang.org/
 [email protected] @mnt_io

    https://www.liip.ch/ https://hoa-project.net http://atoum.org http://tagua.io