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

2019-04-27 Rust

2019-04-27 Rust

#devfestpce

Avatar for Robert Vojta

Robert Vojta

April 27, 2019
Tweet

More Decks by Robert Vojta

Other Decks in Technology

Transcript

  1. Kdo jsem? • Mechovák • Pro neznalé • Mech roste

    na severu a Hradec Králové je na sever od Pardubic • Středověcí hradečáci si utírali zadek mechem gardners.cz Montekové versus Kapuleti, Američani versus Rusáci, Microsoft versus Apple Hradec Králové versus Pardubice
  2. Rust • Multiparadigmatický, kompilovaný programovací jazyk • Vznikl před rokem

    2009 (Graydon Hoare) • Sponzoruje Mozilla • Verze 1.0 byla vydána v roce 2015 • Jako backend používá LLVM
  3. Design • Hodí se pro vysoce paralelní a bezpečné systémy

    • Idiomatický Rust je stejně rychlý jako idiomatické C++ • Syntaxe je podobná C / C++ • Paměťově bezpečný (nezná NULL, neplatné ukazatele, …) • Option, který nabývá hodnoty Some nebo None
  4. Design • Nepoužívá automatickou správu paměti (Garbage Collection) • RAII

    + volitelný „reference counting“ (Rc, Arc, …) • Upřednostňuje „stack allocation“ a nemá implicitní „boxing“ • Použití referencí (&) kontroluje „borrow checker“ při překladu • &T, &mut T, T • Jedna měnitelná reference nebo několik neměnitelných
  5. Design • Typový systém je podobný typovým třídám, říká se

    mu „traity“ (inspirace u Haskellu) • Odvozuje typy kde se dá • Funkce mohou mít generické parametry vyžadující implementaci „traitu“ • Může proběhnout typová kontrola při překladu (C++20) • Generika - monomorfizace - separátní kopie kódu pro jednotlivé instance • Lépe se optimalizuje, prodlužuje čas kompilace a binárka je větší
  6. Instalace $ curl https:!//sh.rustup.rs -sSf | sh source "$HOME/.cargo/env"
 export

    RUST_SRC_PATH="$(rustc !--print sysroot)/lib/rustlib/src/rust/src"
 export DYLD_LIBRARY_PATH="$(rustc !--print sysroot)/lib:$DYLD_LIBRARY_PATH" $ rustup component add clippy $ rustup component add rustfmt $ rustup component add rls $ rustup component add rust-src
  7. Cargo $ cargo new $ cargo build $ cargo clean

    $ cargo check | test | bench $ cargo run $ cargo watch -x test (cargo install cargo-watch)
  8. Dokumentace • The Rust Programming Language - https://doc.rust-lang.org/book/ • The

    Edition Guide - https://doc.rust-lang.org/edition-guide/ • The Rust Standard Library - https://doc.rust-lang.org/std/ • Crates docs - https://docs.rs • The Dark Arts of Advanced and Unsafe Rust Programming • https://doc.rust-lang.org/nomicon/
  9. Hello, World! $ cargo new devfest Created binary (application) `devfest`

    package $ cd devfest $ cargo run Compiling devfest v0.1.0 (/Users/robertvojta/devfest) Finished dev [unoptimized + debuginfo] target(s) in 2.74s Running `target/debug/devfest` Hello, world!
  10. Hello, World! $ tree -I '.git|target' .
 ├── Cargo.lock
 ├──

    Cargo.toml
 └── src
 └── main.rs
 
 1 directory, 3 files
  11. Proměnné & měnitelnost fn main() { let x = 5;

    println!("The value of x is: {}", x); x = 6; println!("The value of x is: {}", x); }
  12. Proměnné & měnitelnost error[E0384]: cannot assign twice to immutable variable

    `x`
 !!--> src/main.rs:4:5
 |
 2 | let x = 5;
 | -
 | |
 | first assignment to `x`
 | help: make this binding mutable: `mut x`
 3 | println!("The value of x is: {}", x);
 4 | x = 6;
 | ^^^^^ cannot assign twice to immutable variable
 
 error: aborting due to previous error
  13. Konstanty & konstantní fce const fn add(a: i32, b: i32)

    !-> i32 { a + b } const FOO: i32 = add(1, 2); fn main() { println!("The value of FOO is: {}", FOO); }
  14. Datové typy & literály !// i8, i16, i32, i64, i128,

    isize (i !-> u) const U: u8 = 10; !// 12_221, 0xff, 0o77, 0b1111_0000, b’A' !// f32, f64 const F: f32 = 10.0; !// 2.0, 33., 12.222_333 !// bool const B: bool = true; !// false !// char const C: char = 'z'; !// ''
  15. Datové typy & literály !// tuple const T: (i32, f64)

    = (10, 30.); !// array const A: [i8; 4] = [1, 2, 3, 4];
  16. Funkce !// bez parametru & navratove hodnoty fn foo() {}

    !// s parametrem fn bar(i: i32) {} !// s parametry & navratovou hodnotou fn sum(a: i32, b: i32) !-> i32 { a + b }
  17. if fn main() { let a = 3; if a

    !== 3 { println!("Yes, 3!"); } else { println!("Hmm !!..."); } }
  18. let & if fn main() { let num = 10;

    let is_odd = if num % 2 !== 0 { true } else { false }; println!("{} is odd {}", num, is_odd); }
  19. loop fn main() { let mut counter = 0; let

    result = loop { counter !+= 1; if counter !== 10 { break counter * 2; } }; println!("The result is {}", result); }
  20. while fn main() { let mut number = 3; while

    number !!= 0 { println!("{}!", number); number = number - 1; } println!("LIFTOFF!!!!!"); }
  21. for fn main() { let a = [10, 20, 30,

    40, 50]; for element in a.iter() { println!("the value is: {}", element); } }
  22. for fn main() { let a = [10, 20, 30,

    40, 50]; for element in a.iter() { println!("the value is: {}", element); } }
  23. Pravidla • Každá hodnota má svého vlastníka • Vlastník může

    být jenom jeden • Když se vlastník dostane mimo „scope“, hodnota se zahodí
  24. Sized & Copy !// Sized = znama velikost pri prekladu

    fn main() { !// Sized !=> stack let a = 10; !// Sized & Copy !=> stack, kopie let b = a; !// Obe promenne jsou stale k dispozici println!("a: {}, b: {}", a, b); }
  25. Move fn main() { !// Heap let a = String!::from("foo");

    !// Move, promenna 'a' prestala existovat let b = a; !// 'a' uz neni k dispozici println!("a: {}, b: {}", a, b); }
  26. Proměnné & měnitelnost error[E0382]: borrow of moved value: `a`
 !!-->

    src/main.rs:4!:30
 |
 2 | let a = String!::from("foo");
 | - move occurs because `a` has type
 `std::string::String`, which does not implement
 the `Copy` trait
 3 | let b = a;
 | - value moved here
 4 | println!("a: {}, b: {}", a, b);
 | ^ value borrowed here after move
  27. Clone fn main() { !// Heap let a = String!::from("foo");

    !// Klon, obe promenne porad existuji let b = a.clone(); println!("a: {}, b: {}", a, b); }
  28. Move fn len(s: String) !-> (String, usize) { let l

    = s.len(); (s, l) } fn main() { !// Heap let a = String!::from("foo"); !// Move - 'a' je predana fci 'len' let (b, l) = len(a); println!("Len of '{}' is {}", b, l); }
  29. Reference !// 's' je reference, ne hodnota fn len(s: &String)

    !-> usize { s.len() } fn main() { let a = String!::from("foo"); !// Predame pomoci reference let l = len(&a); !// 'a' je tu porad s nami println!("Len of '{}' is {}", a, l); }
  30. Měnitelné reference fn add_rust_suffix(s: &mut String) { s.push_str(".rs"); } fn

    main() { let mut a = String!::from("foo"); add_rust_suffix(&mut a); println!("{}", a); }
  31. Reference fn main() { let s = String!::from("foo"); let r1

    = &s; let r2 = &s; println!("{}, {}", r1, r2); }
  32. Reference fn main() { let mut s = String!::from("foo"); let

    r1 = &s; let r2 = &mut s; println!("{}, {}", r1, r2); }
  33. Reference error[E0502]: cannot borrow `s` as mutable because it is

    also
 borrowed as immutable
 !!--> src/main.rs:5:14
 |
 4 | let r1 = &s;
 | -- immutable borrow occurs here
 5 | let r2 = &mut s;
 | ^^^^^^ mutable borrow occurs here
 6 | 
 7 | println!("{}, {}", r1, r2);
 | -- immutable borrow later used here
  34. Reference fn main() { let mut s = String!::from("foo"); let

    r1 = &mut s; let r2 = &mut s; println!("{}, {}", r1, r2); }
  35. Reference error[E0499]: cannot borrow `s` as mutable more than once

    at a time
 !!--> src/main.rs:5:14
 |
 4 | let r1 = &mut s;
 | ------ first mutable borrow occurs here
 5 | let r2 = &mut s;
 | ^^^^^^ second mutable borrow occurs here
 6 | 
 7 | println!("{}, {}", r1, r2);
 | -- first borrow later used here
  36. Reference fn dangle() !-> &String { let s = String!::from("foo");

    &s } fn main() { let reference_to_nothing = dangle(); }
  37. Reference error[E0106]: missing lifetime specifier !!--> src/main.rs:1:16
 |
 1 |

    fn dangle() !-> &String {
 | ^ help: consider giving it a
 | 'static lifetime: `&'static`
 |
 = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
  38. Pravidla • V jeden čas můžete mít • Neomezené množství

    neměnitelných referencí
 
 NEBO • Jednu měnitelnou referenci • Reference jsou vždy platné
  39. Slice fn main() { let a = [5, 4, 3,

    2, 1]; println!("{:?}", &a[1!..2]); !// 4 }
  40. Slice fn first_word(s: &String) !-> Option!<&str> { s.split(' ') .next()

    } fn main() { let mut s = String!::from("hello wolrd"); let first = first_word(&s); s.clear(); println!("First word: {:?}", first); }
  41. Reference error[E0502]: cannot borrow `s` as mutable because it is


    also borrowed as immutable
 !!--> src/main.rs:9:5
 |
 8 | let first = first_word(&s);
 | -- immutable borrow occurs here
 9 | s.clear();
 | ^^^^^^^^^ mutable borrow occurs here
 10 | println!("First word: {:?}", first);
 | ----- immutable borrow
 later used here
  42. Struktury #[derive(Debug)] struct Person { first: String, last: String, }

    impl Person { fn name(&self) !-> String { format!("{} {}", self.first, self.last) } } fn main() { let p = Person { first: "Robert".to_string(), last: "Vojta".to_string(), }; println!("Person {:?} full name {}", p, p.name()); }
  43. Výčty enum IpAddr { IPv4, IPv6 } fn main() {

    let ip = IpAddr!::IPv4; match ip { IpAddr!::IPv4 !=> println!("IPv4"), IpAddr!::IPv6 !=> println!("IPv6"), }; }
  44. Výčty enum IpAddr { IPv4(u8, u8, u8, u8), IPv6(String), }

    fn main() { let ip = IpAddr!::IPv4(127, 0, 0, 1); match ip { IpAddr!::IPv4(a, b, c, d) !=> {
 println!(“IPv4: {}.{}.{}.{}", a, b, c, d); }, IpAddr!::IPv6(x) !=> println!("IPv6: {}", x), }; }
  45. Kolekce fn main() { let v: Vec<u8> = vec![1, 2,

    3, 4]; let mut v2 = vec![1, 2, 3, 4]; for i in &mut v2 { *i !+= 50; } assert_eq!(v2, vec![51, 52, 53, 54]); }
  46. Kolekce fn main() { use std!::collections!::HashMap; let mut scores =

    HashMap!::new(); scores.insert(String!::from("Blue"), 10); scores.insert(String!::from("Yellow"), 50); println!("{}", scores.get("Blue").unwrap_or(&20)); !// 10 println!("{}", scores.get("N/A").unwrap_or(&20)); !// 20 }
  47. Struktury struct Point<T, U> { x: T, y: U, }

    enum OurOption<T> { Some(T), None, }
  48. Funkce fn main() { let number_list = vec![34, 50, 25,

    100, 65]; println!("The largest number is {:?}", largest(&number_list)); let char_list = vec!['y', 'm', 'a', 'q']; println!("The largest char is {:?}", largest(&char_list)); }
  49. Funkce fn largest<T>(list: &[T]) !-> Option!<&T> where T: PartialOrd {

    list.iter() .fold(None, |acc, x| { if let Some(acc) = acc { if x > acc { Some(x) } else { Some(acc) } } else { Some(x) } }) }
  50. Sdílené chování trait Summarize { fn summary(&self) !-> String; }

    struct Person; impl Summarize for Person { fn summary(&self) !-> String { "Person".to_string() } } fn main() { let person = Person {}; println!("{}", person.summary()); }
  51. V parametrech funkcí trait Summarize { … } struct Person;

    impl Summarize for Person {} fn print_summary(x: &impl Summarize) { println!("{}", x.summary()); } fn main() { let person = Person {}; print_summary(&person); }
  52. Generické typy & restrikce fn print_summary<T>(x: &T) where T: Summarize

    { println!("{}", x.summary()); } fn print_summary<T>(x: &T) where T: Summarize + std!::fmt!::Display { println!("Summary '{}' of '{}'", x.summary(), x); }
  53. Návratová hodnota struct Person; impl Summarize for Person {} fn

    summarizable() !-> impl Summarize { Person {} }
  54. Návratová hodnota struct Person; impl Summarize for Person {} struct

    Point; impl Summarize for Point {} fn summarizable_no_way(x: bool) !-> impl Summarize { match x { true !=> Person {}, false !=> Point {}, } }
  55. Podmíněná implementace trait Summarize { fn summary(&self) !-> String {

    "Default summary".to_string() } } trait SummaryPrinter { fn print_summary(&self); } impl<T: Summarize> SummaryPrinter for T { fn print_summary(&self) { format!("Summary: {}", self.summary()); } } struct Person; impl Summarize for Person {} fn main() { let p = Person {}; p.print_summary(); }
  56. Bude fungovat? fn longer(a: &str, b: &str) !-> &str {

    if a.len() > b.len() { a } else { b } } fn main() { let a = "foo"; let b = "bar"; println!("Longer: {}", longer(a, b)); }
  57. Opravená ukázka fn longer<'a>(a: &'a str, b: &'a str) !->

    &'a str { if a.len() > b.len() { a } else { b } } fn main() { let a = "foo"; let b = "bar"; println!("Longer: {}", longer(a, b)); }
  58. Přidané typy fn longer<'a>(a: &'a str, b: &'a str) !->

    &'a str { if a.len() > b.len() { a } else { b } } fn main() { let a: &'static str = "foo"; let l; { let b: &'static str = "bar"; l = longer(a, b); } println!("Longer: {}", l); }
  59. Přidané typy fn longer<'a>(a: &'a str, b: &'a str) !->

    &'a str { if a.len() > b.len() { a } else { b } } fn main() { let a: String = "foo".to_string(); let l; { let b: String = "bar".to_string(); l = longer(&a, &b); } println!("Longer: {}", l); }
  60. Smolík error[E0597]: `b` does not live long enough
 !!--> src/main.rs:11:24


    |
 11 | l = longer(&a, &b);
 | ^^ borrowed value does not live
 | long enough
 12 | }
 | - `b` dropped here while still borrowed
 13 | 
 14 | println!("Longer: {}", l);
 | - borrow later used here
  61. 1. pravidlo // Kazda reference (parametr) ma pridelen vlastni lifetime

    fn foo_elided(x: &i32, y: &i32) {} fn foo<'a, 'b>(x: &'a i32, y: &'b i32) {}
  62. 2. pravidlo // Pokud je na vstupu jenom jeden lifetime,

    vystupni reference // ma stejny fn foo_elided(x: &i32) !-> &i32 { x} fn foo<'a>(x: &'a i32) !-> &'a i32 { x }
  63. 3. pravidlo // Pokud je to metoda a jeden z

    parametru je &self (nebo &mut self), // vystupni lifetime je stejny jako u &self struct Foo { value: i32, } impl Foo { fn bar(&self, x: &str) !-> &i32 { &self.value } }
  64. 3. pravidlo // Pokud je to metoda a jeden z

    parametru je &self (nebo &mut self), // vystupni lifetime je stejny jako u &self struct Foo { value: i32 } impl Foo { fn bar(&self, x: &str) !-> &i32 { &self.value } } impl Foo { fn bar<'a, 'b>(&'a self, x: &'b str) !-> &'a i32 { &self.value } }