Справяне с грешки

25 октомври 2018

Административни неща

Административни неща

Административни неща

Административни неща

Преговор

Преговор

Преговор

Преговор

Конвертиране

Конвертиране

1 2 3 4 5 6 7
struct Celsius(f64);
struct Fahrenheit(f64);
struct Kelvin(f64);

fn room_temperature() -> Fahrenheit {
    Fahrenheit(68.0)
}

Конвертиране

1 2 3 4 5 6 7 8 9 10 11
struct Celsius(f64);
struct Fahrenheit(f64);
struct Kelvin(f64);

fn room_temperature() -> Fahrenheit {
    Fahrenheit(68.0)
}

fn energy_to_heat_water(from: Kelvin, to: Kelvin, mass: f64) -> f64 {
    // whatever
}

Конвертиране

From

1 2 3 4 5 6 7 8 9 10 11
impl From<Celsius> for Kelvin {
    fn from(t: Celsius) -> Kelvin { Kelvin(t.0 + 273.15) }
}

impl From<Fahrenheit> for Celsius {
    fn from(t: Fahrenheit) -> Celsius { Celsius((t.0 - 32) / 1.8) }
}

impl From<Fahrenheit> for Kelvin {
    fn from(t: Fahrenheit) -> Kelvin { Kelvin::from(Celsius::from(t)) }
}

Конвертиране

From

Сега вече можем да си сварим яйца

1 2 3 4 5 6
let e = energy_to_heat_water(
    Kelvin::from(room_temperature()),
    Kelvin::from(Celsius(100.0)),
    1.0
);
println!("Heating water will cost {}J", e);

Конвертиране

From

1 2 3
pub trait From<T> {
    fn from(T) -> Self;
}

Конвертиране

From

1 2 3
pub trait From<T> {
    fn from(T) -> Self;
}

Конвертиране

Into

1 2 3
pub trait Into<T> {
    fn into(self) -> T;
}

Конвертиране

Into

1 2 3
pub trait Into<T> {
    fn into(self) -> T;
}

Конвертиране

Into

1 2 3
pub trait Into<T> {
    fn into(self) -> T;
}

Конвертиране

Into

1 2 3
pub trait Into<T> {
    fn into(self) -> T;
}

Конвертиране

Into

1
impl From<Celsius> for Kelvin {

Е еквивалентно на:

1
impl Into<Kelvin> for Celsius {

Конвертиране

Into

1 2 3 4 5 6 7 8 9 10 11 12 13
// използвайки From
let e = energy_to_heat_water(
    Kelvin::from(room_temperature()),
    Kelvin::from(Celsius(100.0)),
    1.0
);

// използвайки Into
let e = energy_to_heat_water(
    room_temperature().into(),
    Celsius(100.0).into(),
    1.0
);

Конвертиране

Generics

Честа практика е библиотечни функции да не взимат T, а нещо което може да се конвертира до T

1 2 3 4 5 6 7 8 9 10 11
fn energy_to_heat_water<T1, T2>(from: T1, to: T2, mass: f64) -> f64
where
    T1: Into<Kelvin>,
    T2: Into<Kelvin>
{
    let from = from.into();
    let to   = to.into();
    // whatever
}

let e = energy_to_heat_water(room_temperature(), Celsius(100.0), 1.0);

String parsing

String parsing

String parsing

String parsing

FromStr

1 2 3 4 5 6 7 8 9 10
trait FromStr {
    type Err;

    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

String parsing

FromStr

1 2 3 4 5 6 7
use std::str::FromStr;

let x = i32::from_str("-13");
let y = u8::from_str("323");
let z = f32::from_str("5e-3");

println!("{:?}\n{:?}\n{:?}", x, y, z);
Ok(-13) Err(ParseIntError { kind: Overflow }) Ok(0.005)
fn main() {
use std::str::FromStr;

let x = i32::from_str("-13");
let y = u8::from_str("323");
let z = f32::from_str("5e-3");

println!("{:?}\n{:?}\n{:?}", x, y, z);
}

String parsing

parse

Има и по-ергономичен начин

1 2 3 4 5 6 7 8
trait FromStr {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

impl str {
    fn parse<F: FromStr>(&self) -> Result<F, <F as FromStr>::Err> { ... }
}

String parsing

parse

Има и по-ергономичен начин

1 2 3 4 5 6 7 8
trait FromStr {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

impl str {
    fn parse<F: FromStr>(&self) -> Result<F, <F as FromStr>::Err> { ... }
}

String parsing

parse

Има и по-ергономичен начин

1 2 3 4 5 6 7 8
trait FromStr {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

impl str {
    fn parse<F: FromStr>(&self) -> Result<F, <F as FromStr>::Err> { ... }
}

String parsing

parse

Има и по-ергономичен начин

1 2 3 4 5 6 7 8
trait FromStr {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

impl str {
    fn parse<F: FromStr>(&self) -> Result<F, <F as FromStr>::Err> { ... }
}

String parsing

parse

1 2 3 4 5
let x = "-13".parse::<i32>();
let y = "323".parse::<u8>();
let z = "5e-3".parse::<f32>();

println!("{:?}\n{:?}\n{:?}", x, y, z);
Ok(-13) Err(ParseIntError { kind: Overflow }) Ok(0.005)
fn main() {
let x = "-13".parse::();
let y = "323".parse::();
let z = "5e-3".parse::();

println!("{:?}\n{:?}\n{:?}", x, y, z);
}

String parsing

parse

1 2 3 4 5
let x: Result<i32, <i32 as FromStr>::Err> = "-13".parse();
let y: Result<u8, <u8 as FromStr>::Err>   = "323".parse();
let z: Result<f32, <f32 as FromStr>::Err> = "5e-3".parse();

println!("{:?}\n{:?}\n{:?}", x, y, z);
Ok(-13) Err(ParseIntError { kind: Overflow }) Ok(0.005)
use std::str::FromStr;
fn main() {
let x: Result::Err> = "-13".parse();
let y: Result::Err>   = "323".parse();
let z: Result::Err> = "5e-3".parse();

println!("{:?}\n{:?}\n{:?}", x, y, z);
}

String parsing

parse

1 2 3 4 5
let x: Result<i32, _> = "-13".parse();
let y: Result<u8, _>  = "323".parse();
let z: Result<f32, _> = "5e-3".parse();

println!("{:?}\n{:?}\n{:?}", x, y, z);
Ok(-13) Err(ParseIntError { kind: Overflow }) Ok(0.005)
fn main() {
let x: Result = "-13".parse();
let y: Result  = "323".parse();
let z: Result = "5e-3".parse();

println!("{:?}\n{:?}\n{:?}", x, y, z);
}

String parsing

parse

1 2 3 4 5 6
use std::str::FromStr;

#[derive(Debug)]
struct Potato {
    is_a_potato: bool,
}

String parsing

parse

1 2 3 4 5 6 7 8 9 10 11
impl FromStr for Potato {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s == "картоф" {
            Ok(Potato { is_a_potato: true })
        } else {
            Err(String::from("what is this even"))
        }
    }
}
use std::str::FromStr;
#[derive(Debug)]
struct Potato {
is_a_potato: bool,
}
fn main() {
impl FromStr for Potato {
    type Err = String;

    fn from_str(s: &str) -> Result {
        if s == "картоф" {
            Ok(Potato { is_a_potato: true })
        } else {
            Err(String::from("what is this even"))
        }
    }
}
}

String parsing

parse

1 2 3 4 5 6
fn main() {
    let p1: Result<Potato, _> = "картоф".parse();
    let p2: Result<Potato, _> = "патладжан".parse();

    println!("{:?}\n{:?}", p1, p2);
}
Ok(Potato { is_a_potato: true }) Err("what is this even")
use std::str::FromStr;
#[derive(Debug)]
struct Potato {
is_a_potato: bool,
}
impl FromStr for Potato {
type Err = String;
fn from_str(s: &str) -> Result {
if s == "картоф" {
Ok(Potato { is_a_potato: true })
} else {
Err(String::from("what is this even"))
}
}
}
fn main() {
    let p1: Result = "картоф".parse();
    let p2: Result = "патладжан".parse();

    println!("{:?}\n{:?}", p1, p2);
}

String parsing

parse

1 2 3 4 5 6
fn main() {
    let p1 = "картоф".parse::<Potato>();
    let p2 = "патладжан".parse::<Potato>();

    println!("{:?}\n{:?}", p1, p2);
}
Ok(Potato { is_a_potato: true }) Err("what is this even")
use std::str::FromStr;
#[derive(Debug)]
struct Potato {
is_a_potato: bool,
}
impl FromStr for Potato {
type Err = String;
fn from_str(s: &str) -> Result {
if s == "картоф" {
Ok(Potato { is_a_potato: true })
} else {
Err(String::from("what is this even"))
}
}
}
fn main() {
    let p1 = "картоф".parse::();
    let p2 = "патладжан".parse::();

    println!("{:?}\n{:?}", p1, p2);
}

Error handling

Error handling

1 2 3 4 5 6 7 8 9 10 11
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("deep_quotes.txt");

    let mut contents = String::new();
    file.read_to_string(&mut contents);

    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9 10 11
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("deep_quotes.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/bin/main_c656429131e242e34ce39a654c1457567c9b5847.rs:8:10 | 8 | file.read_to_string(&mut contents); | ^^^^^^^^^^^^^^ warning: unused import: `std::io::Read` --> src/bin/main_c656429131e242e34ce39a654c1457567c9b5847.rs:2:5 | 2 | use std::io::Read; | ^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("deep_quotes.txt");

    let mut contents = String::new();
    file.read_to_string(&mut contents);

    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9
enum Result<T, E> {
    Ok(T),
    Err(E),
}

File::open("excellent_file.txt")
    // => Ok(std::fs::File)
File::open("broken_file.txt")
    // => Err(std::io::Error)

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}
Failure is just success rounded down, my friend!
use std::fs::File;
use std::io::Read;

fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = match File::open("shallow_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}
thread 'main' panicked at '😞 No such file or directory (os error 2)', src/bin/main_b45a8bd9ca61aae4e55dda1ed96518a5ab7fe076.rs:7:19 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = match File::open("shallow_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
fn main() {
    let mut deep = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };
    let mut wide = match File::open("wide_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}
Failure is just success rounded down, my friend! F a i l u r e i s j u s t s u c c e s s r o u n d e d d o w n , m y f r i e n d !
use std::fs::File;
use std::io::Read;
fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
let file_contents = "F a i l u r e  i s  j u s t  s u c c e s s  r o u n d e d  d o w n ,  m y  f r i e n d !\n";
std::fs::write("wide_quotes.txt", file_contents.as_bytes()).unwrap();
    let mut deep = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };
    let mut wide = match File::open("wide_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
fn main() {
    all_your_quotes_are_belong_to_us();
}

fn all_your_quotes_are_belong_to_us() {
    let mut deep = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };
    let mut wide = match File::open("wide_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}
Failure is just success rounded down, my friend! F a i l u r e i s j u s t s u c c e s s r o u n d e d d o w n , m y f r i e n d !
use std::fs::File;
use std::io::Read;
fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
let file_contents = "F a i l u r e  i s  j u s t  s u c c e s s  r o u n d e d  d o w n ,  m y  f r i e n d !\n";
std::fs::write("wide_quotes.txt", file_contents.as_bytes()).unwrap();
    all_your_quotes_are_belong_to_us();
}

fn all_your_quotes_are_belong_to_us() {
    let mut deep = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };
    let mut wide = match File::open("wide_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
fn main() {
    match all_your_quotes_are_belong_to_us() {
        Ok(contents) => println!("{}", contents),
        Err(e) => panic!("😞 {}", e),
    }
}

fn all_your_quotes_are_belong_to_us() -> Result<String, io::Error> {
    let mut deep = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => return Err(e),
    };
    let mut wide = match File::open("wide_quotes.txt") {
        Ok(f) => f,
        Err(e) => return Err(e),
    };

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();
    Ok(contents)
}
Failure is just success rounded down, my friend! F a i l u r e i s j u s t s u c c e s s r o u n d e d d o w n , m y f r i e n d !
use std::fs::File;
use std::io::{self, Read};
fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
let file_contents = "F a i l u r e  i s  j u s t  s u c c e s s  r o u n d e d  d o w n ,  m y  f r i e n d !\n";
std::fs::write("wide_quotes.txt", file_contents.as_bytes()).unwrap();
    match all_your_quotes_are_belong_to_us() {
        Ok(contents) => println!("{}", contents),
        Err(e) => panic!("😞 {}", e),
    }
}

fn all_your_quotes_are_belong_to_us() -> Result {
    let mut deep = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => return Err(e),
    };
    let mut wide = match File::open("wide_quotes.txt") {
        Ok(f) => f,
        Err(e) => return Err(e),
    };

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();
    Ok(contents)
}

Error handling

A wild macro appears

1 2 3 4 5 6 7 8
macro_rules! try {
    ($expr:expr) => {
        match $expr {
            Ok(result) => result,
            Err(e) => return Err(e),
        }
    }
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
fn main() {
    match all_your_quotes_are_belong_to_us() {
        Ok(contents) => println!("{}", contents),
        Err(e) => panic!("😞 {}", e),
    }
}

fn all_your_quotes_are_belong_to_us() -> Result<String, io::Error> {
    let mut deep = try!(File::open("deep_quotes.txt"));
    let mut wide = try!(File::open("wide_quotes.txt"));

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();

    Ok(contents)
}
Failure is just success rounded down, my friend! F a i l u r e i s j u s t s u c c e s s r o u n d e d d o w n , m y f r i e n d !
use std::fs::File;
use std::io::{self, Read};
fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
let file_contents = "F a i l u r e  i s  j u s t  s u c c e s s  r o u n d e d  d o w n ,  m y  f r i e n d !\n";
std::fs::write("wide_quotes.txt", file_contents.as_bytes()).unwrap();
    match all_your_quotes_are_belong_to_us() {
        Ok(contents) => println!("{}", contents),
        Err(e) => panic!("😞 {}", e),
    }
}

fn all_your_quotes_are_belong_to_us() -> Result {
    let mut deep = try!(File::open("deep_quotes.txt"));
    let mut wide = try!(File::open("wide_quotes.txt"));

    let mut contents = String::new();
    deep.read_to_string(&mut contents).unwrap();
    wide.read_to_string(&mut contents).unwrap();

    Ok(contents)
}

Error handling

А без онзи unwrap?

1 2 3 4 5 6 7 8 9 10 11
fn main() {
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents); //.unwrap()

    println!("{}", contents);
}

Error handling

А без онзи unwrap?

1 2 3 4 5 6 7 8 9 10 11
fn main() {
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents); //.unwrap()

    println!("{}", contents);
}
warning: unused `std::result::Result` that must be used --> src/bin/main_49027aa658eccb8232022959b2a398cc5125fa37.rs:12:5 | 12 | file.read_to_string(&mut contents); //.unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_must_use)]` on by default = note: this `Result` may be an `Err` variant, which should be handled
use std::fs::File;
use std::io::Read;
fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    file.read_to_string(&mut contents); //.unwrap()

    println!("{}", contents);
}

Error handling

А без онзи unwrap?

1 2 3 4 5 6 7 8 9 10 11
fn main() {
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    let _ = file.read_to_string(&mut contents); // Result<usize, io::Error>

    println!("{}", contents);
}
Failure is just success rounded down, my friend!
use std::fs::File;
use std::io::Read;
fn main() {
let file_contents = "Failure is just success rounded down, my friend!\n";
std::fs::write("deep_quotes.txt", file_contents.as_bytes()).unwrap();
    let mut file = match File::open("deep_quotes.txt") {
        Ok(f) => f,
        Err(e) => panic!("😞 {}", e),
    };

    let mut contents = String::new();
    let _ = file.read_to_string(&mut contents); // Result

    println!("{}", contents);
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
fn main() {
    match all_your_quotes_are_belong_to_us() {
        Ok(contents) => println!("{}", contents),
        Err(e) => panic!("😞 {}", e),
    }
}

fn all_your_quotes_are_belong_to_us() -> Result<String, io::Error> {
    let mut deep = try!(File::open("deep_quotes.txt"));
    let mut wide = try!(File::open("wide_quotes.txt"));

    let mut contents = String::new();
    try!(deep.read_to_string(&mut contents));
    try!(wide.read_to_string(&mut contents));

    Ok(contents)
}

Error handling

Въпрос

1 2 3 4 5
// ??

fn main() {
    try!(all_your_quotes_are_belong_to_us());
}

Error handling

Въпрос

1 2 3
fn main() {
    try!(all_your_quotes_are_belong_to_us());
}
error[E0308]: mismatched types --> src/bin/main_3007932c099000dd4b547ef82819b2138d26a9dd.rs:6:5 | 5 | fn main() { | - expected `()` because of default return type 6 | try!(all_your_quotes_are_belong_to_us()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result` | = note: expected type `()` found type `std::result::Result<_, _>` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
fn all_your_quotes_are_belong_to_us() -> Result<(), String> {
println!("Bla-bla failure success");
Ok(())
}
fn main() {
    try!(all_your_quotes_are_belong_to_us());
}

Error handling

Въпрос

1 2 3 4 5
fn main() -> Result<(), String> {
    try!(all_your_quotes_are_belong_to_us());
    println!("This is okay");
    Ok(())
}
Bla-bla failure success This is okay
fn all_your_quotes_are_belong_to_us() -> Result<(), String> {
println!("Bla-bla failure success");
Ok(())
}
fn main() -> Result<(), String> {
    try!(all_your_quotes_are_belong_to_us());
    println!("This is okay");
    Ok(())
}

Error handling

Въпрос

1 2 3 4
fn main() -> Result<(), String> {
    try!(all_your_quotes_are_belong_to_us());
    Err(String::from("All your Err are belong to us"))
}
Bla-bla failure success Error: "All your Err are belong to us"
fn all_your_quotes_are_belong_to_us() -> Result<(), String> {
println!("Bla-bla failure success");
Ok(())
}
fn main() -> Result<(), String> {
    try!(all_your_quotes_are_belong_to_us());
    Err(String::from("All your Err are belong to us"))
}

Error handling

А ако не са всичките грешки io::Error?

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
fn all_your_numbers_are_belong_to_us() -> Result<i32, io::Error> {
    let mut numbers = try!(File::open("numbers.txt"));

    let mut contents = String::new();
    try!(numbers.read_to_string(&mut contents));

    let n =
        match contents.lines().next() {
            Some(first_line) => try!(first_line.parse::<i32>()),
            None => 0,
        };
    Ok(n)
}

fn main() {
    println!("{:?}", all_your_numbers_are_belong_to_us());
}
error[E0277]: the trait bound `std::io::Error: std::convert::From<std::num::ParseIntError>` is not satisfied --> src/bin/main_3769f80b5739e2290c20f2864bfc454d262a1a78.rs:11:33 | 11 | Some(first_line) => try!(first_line.parse::<i32>()), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::num::ParseIntError>` is not implemented for `std::io::Error` | = help: the following implementations were found: <std::io::Error as std::convert::From<std::ffi::NulError>> <std::io::Error as std::convert::From<std::io::ErrorKind>> <std::io::Error as std::convert::From<std::io::IntoInnerError<W>>> = note: required by `std::convert::From::from` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
use std::fs::File;
use std::io::{self, Read};
fn all_your_numbers_are_belong_to_us() -> Result {
    let mut numbers = try!(File::open("numbers.txt"));

    let mut contents = String::new();
    try!(numbers.read_to_string(&mut contents));

    let n =
        match contents.lines().next() {
            Some(first_line) => try!(first_line.parse::()),
            None => 0,
        };
    Ok(n)
}

fn main() {
    println!("{:?}", all_your_numbers_are_belong_to_us());
}

Error handling

1 2 3 4 5 6 7 8 9 10 11
macro_rules! try {

    ($expr:expr) => {
        match $expr {
            Ok(n) => n,
            //Err(e) => return Err(e),
            Err(e) => return Err(e.into()),
        }
    }

}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13
struct FancyError { message: String }

impl From<io::Error> for FancyError {
    fn from(e: io::Error) -> Self {
        FancyError { message: format!("IO Error: {}", e) }
    }
}

impl From<num::ParseIntError> for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError { message: format!("ParseError: {}", e) }
    }
}

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14
fn all_your_numbers_are_belong_to_us() -> Result<i32, FancyError> {
    let mut numbers = try!(File::open("numbers.txt"));

    let mut contents = String::new();
    try!(numbers.read_to_string(&mut contents));

    let n =
        match contents.lines().next() {
            Some(first_line) => try!(first_line.parse::<i32>()),
            None => 0,
        };

    Ok(n)
}

Error handling

try! използва твърде много скоби и удивителни. И е deprecated.

1 2 3 4 5 6 7 8 9 10
fn all_your_quotes_are_belong_to_us() -> Result<String, io::Error> {
    let mut deep = try!(File::open("deep_quotes.txt"));
    let mut wide = try!(File::open("wide_quotes.txt"));

    let mut contents = String::new();
    try!(deep.read_to_string(&mut contents));
    try!(wide.read_to_string(&mut contents));

    Ok(contents)
}

Error handling

Има по-прост синтаксис:

1 2 3 4 5 6 7 8 9 10
fn all_your_quotes_are_belong_to_us() -> Result<String, io::Error> {
    let mut deep = File::open("deep_quotes.txt")?;
    let mut wide = File::open("wide_quotes.txt")?;

    let mut contents = String::new();
    deep.read_to_string(&mut contents)?;
    wide.read_to_string(&mut contents)?;

    Ok(contents)
}

Error handling

(Има и по-прост метод за четене на файлове:)

1 2 3 4 5 6 7 8 9
use std::fs;
use std::io;

fn all_your_quotes_are_belong_to_us() -> Result<String, io::Error> {
    let mut quotes = String::new();
    quotes.push_str(&fs::read_to_string("deep_quotes.txt")?);
    quotes.push_str(&fs::read_to_string("wide_quotes.txt")?);
    Ok(quotes)
}
use std::fs;
use std::io;

#[allow(dead_code)]
fn all_your_quotes_are_belong_to_us() -> Result {
    let mut quotes = String::new();
    quotes.push_str(&fs::read_to_string("deep_quotes.txt")?);
    quotes.push_str(&fs::read_to_string("wide_quotes.txt")?);
    Ok(quotes)
}
fn main() {
}

Error handling

методи върху Result

1 2 3
let mut fun = File::open("fun.txt").
    or_else(|_error| File::open("passable.txt")).
    or_else(|_error| File::open("okay_i_guess.txt"))?;

Error handling

методи върху Result

1 2 3 4 5 6 7
let optional_fun = File::open("fun.txt").
    or_else(|_error| File::open("passable.txt")).
    or_else(|_error| File::open("okay_i_guess.txt"));

if let Ok(mut fun) = optional_fun {
    // Super-special Fun Time!
}

Error handling

методи върху Result

1 2 3
if let Err(_) = some_side_effects() {
    // Едно warning-че, да се знае...
}

Error handling

методи върху Result

1 2 3 4 5 6 7 8 9 10 11 12 13
let number = "-13".parse::<i32>().unwrap();
let number = "foo".parse::<i32>().unwrap(); // BOOM!

let number = "-13".parse::<i32>().expect("BOOM!");
let number = "foo".parse::<i32>().expect("BOOM!"); // BOOM!

let number = "-13".parse::<i32>().unwrap_or(0);
let number = "foo".parse::<i32>().unwrap_or(0); // 👌

let number = "foo".parse::<i32>().unwrap_or_else(|e| {
    println!("Warning: couldn't parse: {}", e);
    0
});

Panic

Виждали сме panic:

Panic

Виждали сме panic:

Panic

Виждали сме panic:

Panic

Виждали сме panic:

Panic

Какво прави паниката

Panic

Какво прави паниката

Panic

Какво прави паниката

Panic

Какво прави паниката

Panic

Какво прави паниката

Panic

Какво прави паниката

Panic

Какво прави паниката

Panic

Кога?

Panic

Кога?

Panic

Кога?

Panic

Кога?

Error handling

Обобщение

Грешките в rust се разделят на два вида

Error handling

Обобщение

Грешките в rust се разделят на два вида

Error handling

Обобщение

Грешките в rust се разделят на два вида

Error handling

Обобщение

Грешките в rust се разделят на два вида

Error handling

Обобщение

Грешките в rust се разделят на два вида

Интересни пакети

Read & Write

Има стандартни типажи, които ни помагат за четене и писане

Read & Write

std::io::Read

Един от тях е Read

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
pub trait Read {
    // Required:
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;

    // Provided:
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { ... }
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { ... }
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { ... }
    fn by_ref(&mut self) -> &mut Self where Self: Sized { ... }
    fn bytes(self) -> Bytes<Self> where Self: Sized { ... }
    fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized { ... }
    fn take(self, limit: u64) -> Take<Self> where Self: Sized { ... }

    // +nightly:
    unsafe fn initializer(&self) -> Initializer { ... }
}

Read & Write

Бележка:

В модула std::io има следната дефиниция:

1
type Result<T> = Result<T, Error>;

Този синтаксис дефинира type alias ("тип-синоним"). Типа std::io::Result<T> е еквивалентен на Result<T, std::io::Error>.

Това се използва за улеснение, и спокойно може да use-нем std::io и да адресираме io::Result<usize> без да указваме типа за грешка -- той вече е конкретизиран в alias-а.

Read

Имплементира се за някои очаквани структури

1 2 3
impl Read for File
impl Read for Stdin
impl Read for TcpStream

Read

Видяхме как може да четем от файл, а сега и от Stdin

1 2 3 4
use std::io::{self, Read};

let mut buffer = String::new();
io::stdin().read_to_string(&mut buffer)?;

Read & Write

std::io::Write

За писане се използва Write

1 2 3 4 5 6 7 8 9 10
pub trait Write {
    // Required:
    fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
    fn flush(&mut self) -> io::Result<()>;

    // Provided:
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { ... }
    fn write_fmt(&mut self, fmt: Arguments) -> io::Result<()> { ... }
    fn by_ref(&mut self) -> &mut Self where Self: Sized { ... }
}

Write

Както Read се имплементира за очаквани структури

1 2 3 4 5
impl Write for File
impl Write for Stdout
impl Write for Stderr
impl Write for TcpStream
impl Write for Vec<u8>

Write

1 2 3 4 5
use std::fs::File;
use std::io::Write;

let mut f = File::create("foo.txt")?;
f.write_all(b"Hello, world!")?;

Read & Write

Като цяло са интуитивни, но не винаги ефективни когато правим много, но малки операции

BufReader & BufWriter

BufReader & BufWriter

BufReader & BufWriter

BufReader & BufWriter

std::io::BufReader

BufReader е wrapper за структури, които имплементират Read

1 2 3 4 5 6 7 8 9 10 11 12 13
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

fn main() -> Result<(), std::io::Error> {
    let f = File::open("log.txt")?;
    let mut reader = BufReader::new(f);

    let mut line = String::new();
    let len = reader.read_line(&mut line)?;
    println!("First line is {} bytes long", len);
    Ok(())
}
First line is 10 bytes long
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

fn main() -> Result<(), std::io::Error> {
std::fs::write("log.txt", b"Some stuff").unwrap();
    let f = File::open("log.txt")?;
    let mut reader = BufReader::new(f);

    let mut line = String::new();
    let len = reader.read_line(&mut line)?;
    println!("First line is {} bytes long", len);
    Ok(())
}

BufReader & BufWriter

std::io::BufRead

Тук се появява нов метод read_line:

1 2 3 4 5 6 7 8 9 10 11
pub trait BufRead: Read {
    // Required:
    fn fill_buf(&mut self) -> io::Result<&[u8]>;
    fn consume(&mut self, amt: usize);

    // Provided:
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> { ... }
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> { ... }
    fn split(self, byte: u8) -> Split<Self> where Self: Sized { ... }
    fn lines(self) -> Lines<Self> where Self: Sized { ... }
}

BufReader & BufWriter

BufWriter

Подобно, BufWriter е wrapper за структури, които имплементират Write

1 2 3 4 5 6 7 8 9
use std::io::prelude::*;
use std::io::BufWriter;
use std::net::TcpStream;

let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());

for i in 1..10 {
    stream.write(&[i]).unwrap();
}

В този пример чрез BufWriter превръщаме 10 system calls в 1

BufReader & BufWriter

BufWrite

Сори, няма BufWrite :(

BufReader & BufWriter

BufReader & BufWriter

Read & Write

Write може да се използва и за тестване чрез mock

1 2 3 4 5 6 7 8 9 10 11 12 13 14
fn write_u8<W>(writer: &mut W, data: u8) -> io::Result<usize>
where W: Write {
    // Do cool stuff with `writer`
}

#[test]
fn test_write_u8() {
    let mut mock: Vec<u8> = Vec::new();

    write_u8(&mut mock, 42).unwrap();

    assert_eq!(mock.len(), 1);
    assert_eq!(mock[0], 42);
}

Въпроси