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

Въведение в Rust (OpenFest 2017)

Andrew Radev
November 04, 2017

Въведение в Rust (OpenFest 2017)

Andrew Radev

November 04, 2017
Tweet

More Decks by Andrew Radev

Other Decks in Programming

Transcript

  1. Rust е low-level • Без GC • Почти нулев runtime

    • Съвместим със C • Бърз
  2. Rust е high-level • Пакети • Тестване • Елементи от

    функционалното програмиране • Елементи от ООП
  3. Rust е (доста) безопасен • Няма null • Не позволява

    висящи pointer-и • Не позволява double free • Силна статична типова система • Не позволява събирането на flot + int • The Big Deol
  4. fn main() { let x: i32 = 42; let y:

    i32 = x; println!("x = {}", x); println!("y = {}", y); } // =================== x = 42 y = 42
  5. fn main() { let x: char = 'ь'; let y:

    char = x; println!("x = {}", x); println!("y = {}", y); } // =================== x = ь y = ь
  6. fn main() { let x: String = String::from("forty-two"); let y:

    String = x; println!("x = {}", x); println!("y = {}", y); } // =================== error[E0382]: use of moved value: `x` --> src/main.rs:5:24 | 3 | let y: String = x; | - value moved here 4 | 5 | println!("x = {}", x); | ^ value used here after move | = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
  7. fn main() { let x = String::from("forty-two"); if 1 ==

    2 { let local = String::new("Inconceivable!"); println!("{}", local); } // local се деалокира println!("{}", x); } // x се деалокира
  8. fn tell_everybody(news: String) { println!("Ае, хора, {}", news); } fn

    main() { let news = String::from("Извънземните нападат!!!"); tell_everybody(news); // println!("{}", news); // => компилационна грешка }
  9. fn tell_everybody(news: String) -> String { println!("Ае, хора, {}", news);

    news } fn main() { let news = String::from("AI превзе света!!!"); let news_i_got_back = tell_everybody(news); println!("{}", news_i_got_back); // println!("{}", news); // => компилаторна грешка }
  10. fn tell_everybody(news: &String) { println!("Ае, хора, {}", news); } fn

    main() { let news = String::from("50% намаление на репички!!!"); tell_everybody(&news); println!("{}", news); }
  11. Borrow checker • Няма невалидни references • Само един mutable

    ref, или • Колкото си искаме immutable refs
  12. fn main() { let mut fact: String = String::from("Компилатора знае

    две"); fact.push_str("и двеста"); println!("{}", &fact); } // =================== Компилатора знае две и двеста
  13. fn main() { let mut fact: String = String::from("Компилатора знае

    две"); let ending: &str = "и двеста"; fact.push_str(ending); println!("{}", &fact); } // =================== Компилатора знае две и двеста
  14. fn main() { let mut fact: String = String::from("Компилатора знае

    две"); let ending: &str = "и двеста"; fact.push_str(ending); println!("{}", fact); let also_true: &str = &fact[0..32]; println!("{}", also_true); } // =================== Компилатора знае две и двеста Компилатора знае
  15. fn main() { let mut fact: String = String::from("Компилатора знае

    две"); let ending: &str = "и двеста"; String::push_str(&mut fact, ending); let also_true: &str = &fact[0..32]; println!("{}", also_true); } // =================== Компилатора знае
  16. fn main() { let mut fact: String = String::from("Компилатора знае

    две"); let ending: &str = "и двеста"; let fact_reference = &mut fact; String::push_str(fact_reference, ending); let also_true: &str = &fact[0..32]; println!("{}", also_true); } // =================== error[E0502]: cannot borrow `fact` as immutable because it is also borrowed as mutable --> src/main.rs:8:28 | 5 | let fact_reference = &mut fact; | ---- mutable borrow occurs here ... 8 | let also_true: &str = &fact[0..32]; | ^^^^ immutable borrow occurs here 9 | println!("{}", also_true); 10 | } | - mutable borrow ends here
  17. fn main() { let mut fact = String::from("Компилатора знае две");

    let also_true = &fact[0..32]; // NOPE fact.push_str(" и двеста"); }
  18. fn main() { let mut fact = String::from("Компилатора знае две");

    { let also_true = &fact[0..32]; // ... } fact.push_str(" и двеста"); }
  19. fn main() { let lines = { let mut l

    = Vec::with_capacity(4); l.push("Roses are #FF0000,"); l.push("Violets are #0000FF"); l.push("Such a boring example"); l.push("What is wrong with you?"); l }; for line in lines { println!("{}", line); } }
  20. fn main() { let lines = vec![ "Roses are #FF0000",

    "Violets are #0000FF", "Such a boring example", "What is wrong with you?", ]; for line in lines { println!("{}", line); } }
  21. fn main() { let lines = vec![ "Roses are #FF0000",

    "The TARDIS is #0000FF", "A tiny bit better", "With that callback to Doctor Who", ]; for line in lines { println!("{}", line); } }
  22. fn add(a: i32, b: i32) -> i32 { a +

    b } fn main() { let boring_result = add(3, 4); println!("Your boring result: {}", boring_result); } // =================== Your boring result: 7
  23. fn add(a: i32, b: i32) -> i32 { a +

    b } fn main() { let boring_result = add(3.0, 4.0); println!("Your boring result: {}", boring_result); } // =================== error[E0308]: mismatched types --> src/main.rs:6:29 | 6 | let boring_result = add(3.0, 4.0); | ^^^ expected i32, found floating-point variable | = note: expected type `i32` found type `{float}`
  24. fn add<T>(a: T, b: T) -> T { a +

    b } fn main() { let boring_result = add(3.0, 4.0); println!("Your boring result: {}", boring_result); } // =================== error[E0369]: binary operation `+` cannot be applied to type `T` --> src/main.rs:2:5 | 2 | a + b | ^^^^^ | = note: an implementation of `std::ops::Add` might be missing for `T`
  25. use std::ops::Add; fn add<T: Add>(a: T, b: T) -> T::Output

    { a + b } fn main() { let boring_result = add(3.0, 4.0); println!("Your boring result: {}", boring_result); } // =================== Your boring result: 7.0
  26. trait Add<RHS = Self> { type Output; fn add(self, rhs:

    RHS) -> Self::Output; } impl Add< > for VimUser { type Output = fn add(self, rhs: ) -> Self::Output { } }
  27. trait Add<RHS = Self> { type Output; fn add(self, rhs:

    RHS) -> Self::Output; } impl Add<EmacsUser> for VimUser { type Output = fn add(self, rhs: EmacsUser) -> Self::Output { } }
  28. trait Add<RHS = Self> { type Output; fn add(self, rhs:

    RHS) -> Self::Output; } impl Add<EmacsUser> for VimUser { type Output = ProductiveConversation<MutualRespect>; fn add(self, rhs: EmacsUser) -> Self::Output { // Долу стереотипите! } }
  29. use std::fmt::Display; fn main() { let displayable: Vec<&Display> = vec![&5,

    &"baba" as &Display, &3.14]; for d in displayable.iter() { println!("{}", d); } } // The magic of vtables
  30. Zero-cost abstraction C++ implementations obey the zero-overhead principle: What you

    don’t use, you don’t pay for [Stroustrup, 1994]. And further: What you do use, you couldn’t hand code any better. – Stroustrup
  31. fn main() { let potato = " Любов, любов, варен

    картоф, разрежеш го, а той суров. "; println!("--\n{}\n--", potato); } // =================== --- Любов, любов, варен картоф, разрежеш го, а той суров. ---
  32. fn main() { let potato = " Любов, любов, варен

    картоф, разрежеш го, а той суров. "; let lines = potato. trim(). lines(). map(|l| l.trim()); println!("---"); for line in lines { println!("{}", line); } println!("---"); } // =================== --- Любов, любов, варен картоф, разрежеш го, а той суров. ---
  33. fn main() { let potato = " Любов, любов, варен

    картоф, разрежеш го, а той суров. "; let lines = potato. trim(). lines(). map(|l| l.trim()); println!("+-------------------------------+"); for line in lines { println!("| {}\t|", line); } println!("+-------------------------------+"); } // =================== +-------------------------------+ | Любов, любов, варен картоф, | | разрежеш го, а той суров. | +-------------------------------+
  34. let lines = potato. // => &str trim(). lines(). map(|l|

    l.trim()); for line in lines { println!("{}", line); } fn trim(&self) -> &str { // // " Любов, ала-бала, картоф " // ^___________________________^ -> текущия &str // // " Любов, ала-бала, картоф " // ^_____________________^ -> върнатия &str }
  35. let lines = potato. trim(). lines(). // => Lines (std::str::Lines)

    map(|l| l.trim()); for line in lines { println!("{}", line); } // нещо като... impl Iterator for Lines { type Item = &str; fn next() -> Option<Item> { // Some("Любов, любов...") // Some("Картоф, картоф...") // None } } enum Option<T> { Some(T), None, }
  36. let lines = potato. trim(). lines(). map(|l| l.trim()); // =>

    std::iter::Map<std::str::Lines<'_>, [closure@src/main.rs:10:13: 10:25]> for line in lines { println!("{}", line); }
  37. let lines = potato. trim(). lines(). map(|l| l.trim()); for line

    in lines { println!("{}", line); } |l| l.trim() // се превежда до нещо като... struct PotatoClosure { // ... прихванати променливи } impl Fn(&str) -> &str for PotatoClosure { fn call(&self, l: &str) -> &str { l.trim() } }
  38. fn main() { let potato = " Любов, любов, варен

    картоф, разрежеш го, а той суров. "; let lines = potato. trim(). lines(). map(|l| l.trim()); for line in lines { println!("{}", line); } }
  39. fn main() { let potato = String::from(" Любов, любов, варен

    картоф, разрежеш го, а той суров. "); let lines = potato. as_str(). trim(). lines(). map(|l| l.trim()); for line in lines { println!("{}", line); } }
  40. use std::fs::File; use std::io::Read; fn main() { let mut file

    = File::open("boring.txt"); let mut contents = String::new(); file.read_to_string(&mut contents); println!("{}", contents); } //==================== error[E0599]: no method named `read_to_string` found for type `std::result::Result<std::fs::File, std::io::Error>` in the current scope --> src/main.rs:7:7 | 7 | f.read_to_string(&mut contents); | ^^^^^^^^^^^^^^ error: aborting due to previous error
  41. enum Result<T, E> { Ok(T), Err(E), } // Error handling

    in C be like: open("excellent_file.txt", "r") // => 15 open("broken_file.txt") // -1 errno // -17 // In Rust: File::open("excellent_file.txt") // => Ok(File) File::open("broken_file.txt") // => Err("you're err is -17")
  42. use std::fs::File; use std::io::Read; fn main() { let mut file

    = match File::open("boring.txt") { Ok(f) => f, Err(e) => panic!("OH, NO! {}", e), }; let mut contents = String::new(); file.read_to_string(&mut contents); println!("{}", contents); } //==================== Компилационна грешка (ха-ха, това е буквалното съдържание на файла)
  43. use std::fs::File; use std::io::Read; fn main() { do_magic_stuff(); } fn

    do_magic_stuff() { let mut boring = match File::open("boring.txt") { Ok(f) => f, Err(e) => panic!("OH, NO! {}", e), }; let mut fun = match File::open("fun.txt") { Ok(f) => f, Err(e) => panic!("OH, NO! {}", e), }; let mut contents = String::new(); boring.read_to_string(&mut contents); fun.read_to_string(&mut contents); println!("{}", contents); }
  44. use std::fs::File; use std::io::{self, Read}; fn main() { match do_magic_stuff()

    { Ok(contents) => println!("{}", contents), Err(e) => panic!("OH, NO! {}", e), } } fn do_magic_stuff() -> Result<String, io::Error> { let mut boring = match File::open("boring.txt") { Ok(f) => f, Err(e) => return Err(e), }; let mut fun = match File::open("fun.txt") { Ok(f) => f, Err(e) => return Err(e), }; let mut contents = String::new(); boring.read_to_string(&mut contents); fun.read_to_string(&mut contents); return Ok(contents); }
  45. macro_rules! try { ($expr:expr) => { match $expr { Ok(result)

    => result, Err(e) => return Err(e), } } }
  46. use std::fs::File; use std::io::{self, Read}; fn main() { match do_magic_stuff()

    { Ok(contents) => println!("{}", contents), Err(e) => panic!("OH, NO! {}", e), } } fn do_magic_stuff() -> Result<String, io::Error> { let mut boring = match File::open("boring.txt") { Ok(f) => f, Err(e) => return Err(e), }; let mut fun = match File::open("fun.txt") { Ok(f) => f, Err(e) => return Err(e), }; let mut contents = String::new(); boring.read_to_string(&mut contents); fun.read_to_string(&mut contents); return Ok(contents); }
  47. use std::fs::File; use std::io::{self, Read}; fn main() { match do_magic_stuff()

    { Ok(contents) => println!("{}", contents), Err(e) => panic!("OH, NO! {}", e), } } fn do_magic_stuff() -> Result<String, io::Error> { let mut boring = try!(File::open("boring.txt")); let mut fun = try!(File::open("fun.txt")); let mut contents = String::new(); boring.read_to_string(&mut contents); fun.read_to_string(&mut contents); return Ok(contents); }
  48. fn main() { let contents = try!(do_magic_stuff()); println!("{}", contents), }

    //==================== error[E0308]: mismatched types --> src/main.rs:8:30 | 8 | Err(e) => return Err(e), | ^^^^^^ expected (), found enum `std::result::Result` ... 14 | try!(do_magic_stuff()); | ----------------------- in this macro invocation | = note: expected type `()` found type `std::result::Result<_, std::io::Error>`
  49. let mut fun = try!(File::open("fun.txt")); let mut fun = try!

    { File::open("fun.txt"). or_else(|_| File::open("passable.txt")). or_else(|_| File::open("okay_i_guess.txt")) }; let optional_fun = File::open("fun.txt"). or_else(|_| File::open("passable.txt")). or_else(|_| File::open("okay_i_guess.txt")); if let Ok(mut fun) = optional_fun { // Super-special Fun Time! }
  50. fn main() { let args: Vec<String> = std::env::args().collect(); if args.len()

    > 0 { let filename = args.get(0); // Oh, no! Some(String)!
  51. fn main() { let args: Vec<String> = std::env::args().collect(); if args.len()

    > 0 { let filename = args.get(0).unwrap(); run_interpreter(filename) } else { run_console(); } }
  52. fn main() { let args: Vec<String> = std::env::args().collect(); if args.len()

    > 1 { let filename = args.get(1).unwrap(); run_interpreter(filename) } else { run_console(); } }
  53. fn main() { let args: Vec<String> = std::env::args().collect(); if args.len()

    > 2 { let filename = args.get(2).unwrap(); run_interpreter(filename) } else { run_console(); } }
  54. fn main() { let args: Vec<String> = std::env::args().collect(); if args.len()

    >= 3 { let filename = args.get(3).unwrap(); run_interpreter(filename) } else { run_console(); } } // =================== thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /checkout/src/libcore/option.rs:335:20 note: Run with `RUST_BACKTRACE=1` for a backtrace.
  55. fn main() { let args: Vec<String> = std::env::args().collect(); match args.get(0)

    { Some(filename) => run_interpreter(filename), None => run_console(), } }
  56. Заслужава си • Redox (+ coreutils + terminal + shell)

    • Игри (ggez, Piston, SHAR) • 100+ “Friends of Rust”
  57. fn main() { let x: String = String::from("forty-two"); let y:

    String = x; println!("x = {}", x); println!("y = {}", y); } // =================== error[E0382]: use of moved value: `x` --> src/main.rs:5:24 | 3 | let y: String = x; | - value moved here 4 | 5 | println!("x = {}", x); | ^ value used here after move | = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
  58. ust