Slide 1

Slide 1 text

And thou shalt have rigour A gentle introduction to Rust 1

Slide 2

Slide 2 text

Disclaimer I’m no expert! 2

Slide 3

Slide 3 text

• Introduction to language - 20 min • Code Walking - 10 min • Demo - 5 min Agenda 3

Slide 4

Slide 4 text

- Safe, concurrent, systems programming language - 1.0: May 2015, still young! - LLVM backend - Focused on being memory safe - Many, many features! Rust: an overview 4

Slide 5

Slide 5 text

- Guaranteed memory safety! - No GC - No data races - Generics - Traits - Minimal runtime - C bindings - Strongly typed, but with type inference - Excepcional standard library, many zero-cost abstractions, including concurrency primitives Rust: the good 5

Slide 6

Slide 6 text

- Pattern matching - Move semantics - Option and Result, no exceptions - Most advanced ownership system out there - Compile time borrow checker - Lifetimes Rust: the good 6

Slide 7

Slide 7 text

- Lots of syntax - Memory model difficult to grasp - Steep learning curve - No C++ bindings :( - Somewhat small community, growing every day! Rust: the bad 7

Slide 8

Slide 8 text

C++ int main() { std::vector v; v.push_back(“Hello"); std::string& x = v[0]; v.push_back(“world"); std::cout << x; } Borrow checker sample Rust fn main() { let mut v = vec![]; v.push(“Hello"); let w = &v[0]; v.push(“world"); println!("{} world", w); } 8

Slide 9

Slide 9 text

C++ g++ borrow.cpp -o borrow *[1] 1827 segmentation fault ./borrow valgrind ./borrow ==13521== HEAP SUMMARY: ==13521== in use at exit: 39,759 bytes in 429 blocks ==13521== total heap usage: 510 allocs, 81 frees, 45,991 bytes allocated ==13521== ==13521== LEAK SUMMARY: ==13521== definitely lost: 0 bytes in 0 blocks ==13521== indirectly lost: 0 bytes in 0 blocks ==13521== possibly lost: 0 bytes in 0 blocks ==13521== still reachable: 4,096 bytes in 1 blocks ==13521== suppressed: 35,663 bytes in 428 blocks ==13521== Rerun with --leak-check=full to see details of leaked memory ==13521== ==13521== For counts of detected and suppressed errors, rerun with: -v ==13521== ERROR SUMMARY: 8 errors from 4 contexts (suppressed: 0 from 0) Borrow checker sample 9

Slide 10

Slide 10 text

¡Qué desastre! Borrow checker sample 10

Slide 11

Slide 11 text

Borrow checker sample borrow.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable borrow.rs:8 v.push("world"); ^ borrow.rs:6:11: 6:12 note: previous borrow of `v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `v` until the borrow ends borrow.rs:6 let w = &v[0]; ^ borrow.rs:11:2: 11:2 note: previous borrow ends here borrow.rs:1 fn main() { ... borrow.rs:11 } ^ error: aborting due to previous error 11

Slide 12

Slide 12 text

Not even compiles! Borrow checker sample 12

Slide 13

Slide 13 text

fn main() { // Variables can be type annotated. let logical: bool = true; let a_float: f64 = 1.0; // Regular annotation let an_integer = 5i32; // Suffix annotation // Or a default will be used. let default_float = 3.0; // `f64` let default_integer = 7; // `i32` let tuple = (1u8, 2u16, 3u32, 4u64, -1i8, -2i16, -3i32, -4i64, 0.1f32, 0.2f64, 'a', true); // Values can be extracted from the tuple using tuple indexing println!("long tuple first value: {}", long_tuple.0); } Primitives 13

Slide 14

Slide 14 text

Array and slices fn main() { let xs: [i32; 5] = [1, 2, 3, 4, 5]; // All elements can be initialized to the same value let ys: [i32; 500] = [0; 500]; println!("first element of the array: {}", xs[0]); println!("array size: {}", xs.len()); // Arrays can be automatically borrowed as slices println!("borrow the whole array as a slice"); analyze_slice(&xs); println!("borrow a section of the array as a slice"); analyze_slice(&ys[1 .. 4]); // borrow a section of the slice! } fn analyze_slice(slice: &[i32]) { println!("first element of the slice: {}", slice[0]); println!("the slice has {} elements", slice.len()); } Arrays and slices 14

Slide 15

Slide 15 text

struct Point { x: f64, y: f64, } // instantiate let point: Point = Point { x: 1, y: 1} // or with type inference let point = Point { x: 1, y: 1} let x = Point.x; Structs and enums 15

Slide 16

Slide 16 text

enum Person { // An `enum` may either be `unit-like` (like C) Skinny, Fat, // like tuple structs, Height(i32), Weight(i32), // or like structures. Info { name: String, height: i32 } } fn main() { let person = Person::Height(18); let danny = Person::Weight(10); let dave = Person::Info {name: "Dave".to_owned(), height: 72}; let john = Person::Fat; let larry = Person::Skinny; } Structs and enums 16

Slide 17

Slide 17 text

if n < 0 { // do stuff! } // if are expressions! let n_less_than_0 = if n < 0 { true }; // while and for/range while n < 0 { // do stuff! } for i in range 1..100 { // do 100 stuffs! } loop { // infinite loop } Flow control 17

Slide 18

Slide 18 text

let number = 13; match number { 1 => println!("One!"), // match single 2 | 3 | 5 | 7 | 11 => println!("This is a prime"), // match OR 13...19 => println!("A teen"), // match range _ => println!("Ain't special"), // rest of cases } let boolean = true; // match is an expression too! let binary: u8 = match boolean { false => 0, true => 1, }; let pair = (0, -2); // match works with tuples, enums, structs, etc aswell (destructuring) match pair { (0, y) => println!("First is `0` and `y` is `{:?}`", y), (x, 0) => println!("`x` is `{:?}` and last is `0`", x), } Flow control: pattern matching 18

Slide 19

Slide 19 text

fn sample_function(s: &str, p: Point) -> bool { true // when no ";", this will be returned } struct Point { x: f64, y: f64, } impl Point { fn new(x: f64, y: f64) -> Point { Point { x: x, y: y } } fn do_something(&mut self) -> bool { self.x = 10; return true; // can also use "return" } } let point = Point::new(); point.do_something() sample_function("", point); Functions and methods 19

Slide 20

Slide 20 text

let convert_bin_to_bool = |number: u8| -> bool { match number { 1 => true, 0 => false, _ => panic!("No binary number!"), } }; let my_number = 0; println!("This is: {}", convert_bin_to_bool(my_number)); Closures 20

Slide 21

Slide 21 text

// in functions fn im_generic(s: Vec) { } // in structs struct GenericStruct; // specialization impl GenericStruct { } // generic impl GenericStruct { } Generics 21

Slide 22

Slide 22 text

struct MySqlDriver { host: String, username: String, password: String, } trait DatabaseDriver { // static fn new() -> Self; // instance methods fn connect(&self) -> bool; fn do_something(&self, data: i32) -> i32; // default implementation fn name(&self) -> &'static str { "driver" } } Traits impl DatabaseDriver for MySqlDriver { fn new() { MySqlDriver { ... } } fn connect(&self) { self.do_connect(self.host, ...); } fn do_something(&self, data: i32) { ... } } impl MySqlDriver { fn another_method_not_in_trait() { ... } } 22

Slide 23

Slide 23 text

macro_rules! say_hello { () => ( // <- these are macro arguments println!("Hello!"); ) } fn main() { // this call will expand into `println!("Hello");` say_hello!() // built-in macros println!("hello there"); panic!("this is shit"); // used for testing assert!(5 > 6); assert_eq!(true, false); } Macros 23

Slide 24

Slide 24 text

mod my_module { fn test() { println!("this is private"); } pub fn test_public() { println!("this is public!"); } pub mod recursive { pub fn im_deep_inside() { println!("indeed"); } } } fn main () { my_module::test_public(); // <- works my_module::recursive::im_deep_inside(); // indeed! my_module::test(); // no way men } Modules 24

Slide 25

Slide 25 text

// example: test #[test] fn this_is_a_test() { ... } #[cfg(target_os = "linux")] fn are_you_on_linux() { println!("You are running linux!") } #[cfg(not(target_os = "linux"))] fn are_you_on_linux() { println!("You are *not* running linux!") } // also as macro! if cfg!(target_os = "linux") { println!("Yes. It's definitely linux!"); } else { println!("Yes. It's definitely *not* linux!"); } Attributes 25

Slide 26

Slide 26 text

enum Result { Ok(T), Err(E) } fn my_function() -> Result { if some_condition { Ok("Here is your data".to_string()) } else { Err(100) } } match my_function() { Ok(v) => println!("{}", v), Err(e) => println!("This is a disaster: {}", e), } // also try! this will panic when Err is found! let my_ok_value = try!(my_function()); Result 26

Slide 27

Slide 27 text

pub enum Option { None, Some(T), } fn divide(numerator: f64, denominator: f64) -> Option { if denominator == 0.0 { None } else { Some(numerator / denominator) } } let result = divide(2.0, 3.0); // -> Option! match result { Some(x) => println!("Result: {}", x), None => println!("Cannot divide by 0"), } Option 27

Slide 28

Slide 28 text

fn destroy_box(c: Box) { // now I own Box! } // Box will be destroyed out of the scope here fn main() { let a = Box::new(100); println!("a contains: {}", a); let b = a; // now b owns the Box println!("a contains: {}", a); // ERROR destroy_box(b); // moving Box to the function println!("b contains: {}", b); // ERROR } Move semantics 28

Slide 29

Slide 29 text

fn eat_box(boxed_int: Box) { println!("destroying box that contains {}", boxed_int); } // box goes out of scope, destroy! fn peep_inside_box(borrowed_int: &i32) { println!("This int is: {}", borrowed_int); } fn main() { let boxed_int = Box::new(5); peep_inside_box(&boxed_int); // ownership is intact! { let _boxed_int_ref: &i32 = &boxed_int; eat_box(boxed_int); // ERROR } // boxed_int_ref goes out of scope, destroy! eat_box(boxed_int); } Borrowing 29

Slide 30

Slide 30 text

Lifetimes 30 https://play.rust-lang.org/? gist=3b670d9b30d232ac644c&version=stable

Slide 31

Slide 31 text

use std::collections::HashMap; let mut book_reviews = HashMap::new(); // type inference! book_reviews.insert("Whatever", "Awesome!"); book_reviews.contains_key("Les Mis√érables"); book_reviews.remove("Whatever"); std: collections 31 • Sequences: Vec, VecDeque, LinkedList • Maps: HashMap, BTreeMap • Sets: HashSet, BTreeSet • Misc: BinaryHeap

Slide 32

Slide 32 text

fn main() { let boxed_data: Box = Box::new(1000); // remove layer of indirection // copied to the stack! let raw_data = *boxed_data; } // I'm cleaned here std: Box 32 • Heap allocated data • Like “unique_ptr” in C++ • Memory automatically freed when out-of-scope

Slide 33

Slide 33 text

use std::sync::Arc; use std::thread; let numbers: Vec<_> = (0..100u32).collect(); let shared_numbers = Arc::new(numbers); for _ in 0..10 { let child_numbers = shared_numbers.clone(); // move 'child_numbers' to the thread, work locally thread::spawn(move || { let local_numbers = &child_numbers[..]; }); } std::sync 33 • Multiple sync primitives: Arc, Barrier, Mutex, Once, etc. • Also mpsc (channels)

Slide 34

Slide 34 text

use std::thread; use std::sync::mpsc::channel; // Create a simple streaming channel let (tx, rx) = channel(); thread::spawn(move|| { tx.send(10).unwrap(); }); assert_eq!(rx.recv().unwrap(), 10); std::mpsc (channels) 34 • Multi-producer, single-consumer FIFO queue communication primitives • Like Go but a little bit more syntax

Slide 35

Slide 35 text

std: many other things 35 • Atomics: AtomicBool, AtomicPtr, etc. • std::cmp, comparisons: Eq, PartialEq, etc. • IO: std::io, std::net (TcpListener, etc.) • Iterators: Chain, Cycle, Once, Map, etc. • Processes: std::process, run command, pipes, etc. • Most of these expose traits, so you can extend your structures this way!

Slide 36

Slide 36 text

Code Walking 36 • Redis clone • Made to illustrate introductory Rust usage • Fully commented and unit tested • Functional: GET, SET, DEL, EXISTS, SADD, SREM, SISMEMBER, SMEMBERS • Just clone, make, and enjoy! • https://github.com/albertofem/carcasian

Slide 37

Slide 37 text

Demo 37 Let’s put Rust to real world use!

Slide 38

Slide 38 text

Links 38 Official page: http://rust-lang.org Book: http://doc.rust-lang.org/book/ Reference: https://doc.rust-lang.org/stable/reference.html Cargo crates: https://crates.io/ Rust by example: http://rustbyexample.com

Slide 39

Slide 39 text

println!(“{}”, “The End!”); 39 Q&A