Whoami • Florian Gilcher • https://twitter.com/argorak • https://github.com/skade • CEO https://asquera.de, https://ferrous-systems.com • Rust Programmer and Trainer: https://rust-experts.com • Mozillian • Previously 10 years of Ruby community work 3
Whoami • Started learning Rust in 2013 • Mostly out of personal curiosity • Co-Founded the Berlin usergroup • Organized RustFest and OxidizeConf • Project member since 2015, mostly Community team 4
A simple example #[derive(Debug)] struct Point { x: i32, y: i32 } fn print_point(p: &Point ) { println!("{:?}" , p) } Point implements Debug The println macro requires the printed value to implement Debug We pass Point as a concrete type 7
Let’s be generic fn print(s: &S) where S: Debug { println!("{:?}", s) } The function is generic over a type variable S It takes a reference to a value of the type S S can be any type, as long as it implements Debug. This is called a trait bound. 9
Let’s be generic fn main() { let p = Point { x: 0, y: 0 }; let s = Square { x: 0, y: 0, width: 0 }; print::(&p); print::(&s); } Both functions are actually different and are created on use. A function logically existing and actually being compiled is two things. 11
Detailed analysis fn some_function where T: Trait, T: OtherTrait, E: Trait + OtherTrait { } In the where clase, T is an actual type Types can be constrained multiple times Read: ”for every type pair T and E, where T is Send + Sync and E is Send” 13
Detailed analysis Because the left hand is an actual type, this works: fn takes_into_string(t: T) where String: From { let string = String::from(t); println!("{}", string); } 14
Associated types The where clause can be used to constrain the associated type of a trait: fn debug_iter(iter: I) where I: Iterator, I::Item: Debug { for item in iter { println!("{:?}", iter); } } 15
The thread API fn main() { let vec = vec![1,2,3,4]; let handler = std::thread::spawn(move { vec.iter().count() }); let number = handler.join().unwrap(); println!("{}", number); } 20
The thread API pub fn spawn(f: F) -> JoinHandle where F: FnOnce() -> T, { /*...*/ } pub fn spawn(f: &'a i32) -> JoinHandle<&'a i32> pub fn spawn(f: std::slice::Iter<'a, T>) -> JoinHandle This is the closure I’m cheating a little, this is the closure capture type The compiler checks all potential situations! 21
Opting out of Borrowing pub fn spawn(f: F) -> JoinHandle where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static { //... } This is the closure Send is one of Rust concurrency guards ’static asks for the type to own all data This is not cheating! 22
Late bounds struct Wrapper where I: Debug { inner: I } fn take_inner(w: Wrapper) -> I where I: Debug { w.inner } This is necessary because the type mandates item, it isn’t useful to the function 23
Late bounds impl Wrapper { pub fn new(d: I) -> Self where I: Debug { Wrapper { inner: d } } pub fn inspect(&self) where I: Debug { println!("{:?}", self.inner); } } new ensures that Wrapper only ever can be constructed with Debug types 26
Terrible clauses impl Execute for Find> where R: Relation, Repos: Repository, Repos::Gateway: ExecuteOne, Self: Query { type FutureType = <::Gateway as ExecuteOne< Self::Parameters>>::Future; fn execute(&self, repos: &Repos) -> Self::FutureType where Repos: Stores { ExecuteOne::execute_query(repos.gateway(), &self) } } These things don’t out of the blue and are frequently changed. 32
State Machines struct Start; impl State for Start {} struct Loop; impl State for Loop {} struct Stop; impl State for Stop {} impl TerminalState for Stop {} 37
State Machines fn main() { let initial = Start; let next: Loop = initial.transition(); let next: Loop = next.transition(); //next.terminate() //let next: Start = next.transition(); let next: End = next.transition(); next.terminate() } The setup is a little involved, but usage is straight-forward and safe! https://hoverbear.org/2016/10/12/rust-state-machine-pattern/ 39
Conclusion • Getting comfortable with the power of the where clause is important • Exactly picking which constraints you need where is key • There’s creative patterns of interplay 44