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

24 октомври 2024

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

Преговор

Преговор

Преговор

Преговор

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

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

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: Kg) -> Joule {
    // whatever
}
fn main() {}
struct Celsius(f64);
struct Fahrenheit(f64);
struct Kelvin(f64);
struct Kg(f64);
struct Joule(f64);

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

fn energy_to_heat_water(from: Kelvin, to: Kelvin, mass: Kg) -> Joule {
    // whatever
todo!()
}

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

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)),
    Kg(1.0)
);
println!("Heating water will cost {}J", e);

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

From

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

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

From

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

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

From

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

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

From

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

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

From

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

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

From

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

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

From

1 2 3
pub trait From<T> {
    fn from(value: T) -> Self;
}
fn main() {}
pub trait From {
    fn from(value: T) -> Self;
}
1 2
u64::from(val: u32)
u64::from(val: u16)

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

From

1 2 3
pub trait From<T> {
    fn from(value: T) -> Self;
}
fn main() {}
pub trait From {
    fn from(value: T) -> Self;
}
1 2
<u64 as From<u32>>::from(val: u32)
<u64 as From<u16>>::from(val: u16)

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

Into

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

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

Into

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

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

Info

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

Info

1 2 3 4 5 6
impl<T, U> Into<U> for T
where
    U: From<T>
{
    /* ... */
}

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

Info

1 2 3 4 5 6
impl<T, U> Into<U> for T
where
    U: From<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)),
    Kg(1.0)
);

// използвайки Into
let e = energy_to_heat_water(
    room_temperature().into(),
    Celsius(100.0).into(),
    Kg(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: Kg) -> Joule
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), Kg(1.0));
fn main() {
struct Kelvin(f64);
struct Celsius(f64);
struct Kg(f64);
struct Joule(f64);
impl From for Kelvin { fn from(k: Celsius) -> Kelvin { todo!() } }
fn room_temperature() -> Celsius { todo!(); }

fn energy_to_heat_water(from: T1, to: T2, mass: Kg) -> Joule
where
    T1: Into,
    T2: Into
{
    let from = from.into();
    let to   = to.into();
    // whatever
todo!()
}

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

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

Into

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

Into

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

Into

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

Into

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

Into

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: PosOverflow }) 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

И тук има реципрочен метод

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: PosOverflow }) 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: PosOverflow }) 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: PosOverflow }) 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
let x: i32   = "-13".parse().unwrap();
// let y: u8 = "323".parse().unwrap();
let z: f32   = "5e-3".parse().unwrap();

println!("{:?}\n???\n{:?}", x, z);
-13 ??? 0.005
fn main() {
let x: i32   = "-13".parse().unwrap();
// let y: u8 = "323".parse().unwrap();
let z: f32   = "5e-3".parse().unwrap();

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

String parsing

parse

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

#[derive(Debug)]
struct Student {
    name: String,
    faculty_number: String,
}

String parsing

parse

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
impl FromStr for Student {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.split(", ").collect::<Vec<_>>().as_slice() {
            [name, faculty_number] => {
                let name = name.to_string();
                let faculty_number = faculty_number.to_string();

                Ok(Self { name, faculty_number })
            },
            _ => Err(String::from("🤷🤷🤷")),
        }
    }
}
use std::str::FromStr;
#[derive(Debug)]
struct Student {
name: String,
faculty_number: String,
}
fn main() {
impl FromStr for Student {
    type Err = String;

    fn from_str(s: &str) -> Result {
        match s.split(", ").collect::>().as_slice() {
            [name, faculty_number] => {
                let name = name.to_string();
                let faculty_number = faculty_number.to_string();

                Ok(Self { name, faculty_number })
            },
            _ => Err(String::from("🤷🤷🤷")),
        }
    }
}
}

String parsing

parse

1 2 3 4 5 6 7
fn main() {
    let s1: Result<Student, _> = "Данчо Е. Студент, 12345".parse();
    let s2: Result<Student, _> = "Гинка Билоба, 77777".parse();
    let s3: Result<Student, _> = "Бял Мерцедес".parse();

    println!("{:?}\n{:?}\n{:?}", s1, s2, s3);
}
Ok(Student { name: "Данчо Е. Студент", faculty_number: "12345" }) Ok(Student { name: "Гинка Билоба", faculty_number: "77777" }) Err("🤷🤷🤷")
use std::str::FromStr;
#[derive(Debug)]
struct Student {
name: String,
faculty_number: String,
}
impl FromStr for Student {
type Err = String;
fn from_str(s: &str) -> Result {
match s.split(", ").collect::>().as_slice() {
[name, faculty_number] => {
let name = name.to_string();
let faculty_number = faculty_number.to_string();
Ok(Self { name, faculty_number })
},
_ => Err(String::from("🤷🤷🤷")),
}
}
}
fn main() {
    let s1: Result = "Данчо Е. Студент, 12345".parse();
    let s2: Result = "Гинка Билоба, 77777".parse();
    let s3: Result = "Бял Мерцедес".parse();

    println!("{:?}\n{:?}\n{:?}", s1, s2, s3);
}

String parsing

parse

1 2 3 4 5 6 7
fn main() {
    let s1 = "Данчо Е. Студент, 12345".parse::<Student>();
    let s2 = "Гинка Билоба, 77777".parse::<Student>();
    let s3 = "Бял Мерцедес".parse::<Student>();

    println!("{:?}\n{:?}\n{:?}", s1, s2, s3);
}
Ok(Student { name: "Данчо Е. Студент", faculty_number: "12345" }) Ok(Student { name: "Гинка Билоба", faculty_number: "77777" }) Err("🤷🤷🤷")
use std::str::FromStr;
#[derive(Debug)]
struct Student {
name: String,
faculty_number: String,
}
impl FromStr for Student {
type Err = String;
fn from_str(s: &str) -> Result {
match s.split(", ").collect::>().as_slice() {
[name, faculty_number] => {
let name = name.to_string();
let faculty_number = faculty_number.to_string();
Ok(Self { name, faculty_number })
},
_ => Err(String::from("🤷🤷🤷")),
}
}
}
fn main() {
    let s1 = "Данчо Е. Студент, 12345".parse::();
    let s2 = "Гинка Билоба, 77777".parse::();
    let s3 = "Бял Мерцедес".parse::();

    println!("{:?}\n{:?}\n{:?}", s1, s2, s3);
}

String parsing

невъзможни грешки

Асоциирания тип Err връща информация защо конвертирането е било неуспешно

1 2 3 4 5 6 7
impl FromStr for i32 {
    type Err = ParseIntError;

    fn from_str(src: &str) -> Result<Self, ParseIntError> {
        ...
    }
}

String parsing

невъзможни грешки

Но какво да върнем, ако конвертирането е винаги успешно?

1 2 3 4 5 6 7
impl FromStr for String {
    type Err = ???;

    fn from_str(s: &str) -> Result<String, Self::Err> {
        Ok(String::from(s))
    }
}

String parsing

невъзможни грешки

Можем да върнем (), защото нямаме информация за грешка ..

1 2 3 4 5 6 7
impl FromStr for String {
    type Err = ();

    fn from_str(s: &str) -> Result<String, Self::Err> {
        Ok(String::from(s))
    }
}

String parsing

невъзможни грешки

.. но има по-добър вариант - Infallible

1 2 3 4 5 6 7
impl FromStr for String {
    type Err = std::convert::Infallible;

    fn from_str(s: &str) -> Result<String, Self::Err> {
        Ok(String::from(s))
    }
}

String parsing

невъзможни грешки

Какво е Infallible?

1
enum Infallible {}

String parsing

невъзможни грешки

Какво е Infallible?

1
enum Infallible {}

Празни типове

На типовете можем да гледаме като на множества от стойности

1 2
bool = { true, false }
u32 = { 0, 1, ..., 2**32-1 }

Празните структури са типове с точно една възможна стойност - нула бита информация

1 2 3 4
() = { () }

struct Empty;
Empty = { Empty }

Празни типове

Празните енуми са типове с нула възможни стойности - празното множество.

1 2 3
enum Never {}

Never = { }

Стойност от тип Never не може да съжествува в програмата

Празни типове

Това значи, че парче код, което съдържа стойност от тип Never никога не би се изпълнило

1 2 3 4 5 6 7 8
let x: Never = some_expression();
something_else();

// за компилатора е еквиваленто на

some_expression();
// unreachable!!
// something_else();

String parsing

невъзможни грешки

Това е удобно, когато искаме да изразим невъзможна грешка

1 2 3 4 5 6 7 8
match "some string".parse::<String>() {
    Ok(s) => {  // Ok(String)
        println!("{s}");
    }
    Err(_) => { // Err(Infallible)
        println!("this code is, actually, unreachable");
    }
}
some string
fn main() {
match "some string".parse::() {
    Ok(s) => {  // Ok(String)
        println!("{s}");
    }
    Err(_) => { // Err(Infallible)
        println!("this code is, actually, unreachable");
    }
}
}

String parsing

невъзможни грешки

Защото компилатора може да види, че единия ръкав е недостижим

1 2 3 4 5
match "some string".parse::<String>() {
    Ok(s) => {
        println!("{s}");
    }
}
some string
fn main() {
match "some string".parse::() {
    Ok(s) => {
        println!("{s}");
    }
}
}

String parsing

невъзможни грешки

Защото компилатора може да види, че единия ръкав е недостижим

1 2 3 4 5
match "some string".parse::<String>() {
    Ok(s) => {
        println!("{s}");
    }
}
some string
fn main() {
match "some string".parse::() {
    Ok(s) => {
        println!("{s}");
    }
}
}

String parsing

невъзможни грешки

Това също е позволено

1
let Ok(s) = "some text".parse::<String>();
fn main() {
let Ok(s) = "some text".parse::();
}

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 enum `Result` in the current scope --> src/bin/main_c656429131e242e34ce39a654c1457567c9b5847.rs:8:10 | 8 | file.read_to_string(&mut contents); | ^^^^^^^^^^^^^^ method not found in `Result<File, Error>` | note: the method `read_to_string` exists on the type `File` --> /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/io/mod.rs:904:5 help: consider using `Result::expect` to unwrap the `File` value, panicking if the value is a `Result::Err` | 8 | file.expect("REASON").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 For more information about this error, try `rustc --explain E0599`. error: could not compile `rust` (bin "main_c656429131e242e34ce39a654c1457567c9b5847") due to 1 previous error; 1 warning emitted
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 src/bin/main_b45a8bd9ca61aae4e55dda1ed96518a5ab7fe076.rs:7:19: 😞 No such file or directory (os error 2) 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 !
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(result) => result,
Err(e) => return Err(e),
}
}
}
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 `Result` that must be used --> src/bin/main_49027aa658eccb8232022959b2a398cc5125fa37.rs:12:5 | 12 | file.read_to_string(&mut contents); //.unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this `Result` may be an `Err` variant, which should be handled = note: `#[warn(unused_must_use)]` on by default help: use `let _ = ...` to ignore the resulting value | 12 | let _ = file.read_to_string(&mut contents); //.unwrap() | +++++++
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_9eba2fc2a4227809e15aa229a57457e11de4aae5.rs:5:18 | 5 | Err(e) => return Err(e), | ^^^^^^ expected `()`, found `Result<_, Error>` ... 13 | fn main() { | - expected `()` because of default return type 14 | try_!(all_your_quotes_are_belong_to_us()); | ----------------------------------------- in this macro invocation | = note: expected unit type `()` found enum `Result<_, std::io::Error>` = note: this error originates in the macro `try_` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0308`. error: could not compile `rust` (bin "main_9eba2fc2a4227809e15aa229a57457e11de4aae5") due to 1 previous error
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(result) => result,
Err(e) => return Err(e),
}
}
}
fn all_your_quotes_are_belong_to_us() -> Result<(), std::io::Error> {
println!("Bla-bla failure success");
Ok(())
}
fn main() {
    try_!(all_your_quotes_are_belong_to_us());
}

Error handling

Въпрос

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

fn main() -> Result<(), io::Error> {
    try_!(all_your_quotes_are_belong_to_us());
    println!("This is okay");
    Ok(())
}
Bla-bla failure success This is okay
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(result) => result,
Err(e) => return Err(e),
}
}
}
fn all_your_quotes_are_belong_to_us() -> Result<(), std::io::Error> {
println!("Bla-bla failure success");
Ok(())
}
use std::io;

fn main() -> Result<(), io::Error> {
    try_!(all_your_quotes_are_belong_to_us());
    println!("This is okay");
    Ok(())
}

Error handling

Въпрос

1 2 3 4 5 6
use std::io;

fn main() -> Result<(), io::Error> {
    try_!(all_your_quotes_are_belong_to_us());
    Err(io::Error::new(io::ErrorKind::Other, "oh no!"))
}
Bla-bla failure success Error: Custom { kind: Other, error: "oh no!" }
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(result) => result,
Err(e) => return Err(e),
}
}
}
fn all_your_quotes_are_belong_to_us() -> Result<(), std::io::Error> {
println!("Bla-bla failure success");
Ok(())
}
use std::io;

fn main() -> Result<(), io::Error> {
    try_!(all_your_quotes_are_belong_to_us());
    Err(io::Error::new(io::ErrorKind::Other, "oh no!"))
}

Error handling

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

Error handling

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
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[E0308]: mismatched types --> src/bin/main_73960cf9c502217fe914332a7bf49e44b6dcf3f2.rs:5:22 | 5 | Err(e) => return Err(e), | --- ^ expected `Error`, found `ParseIntError` | | | arguments to this enum variant are incorrect ... 18 | Some(first_line) => try_!(first_line.parse::<i32>()), | -------------------------------- in this macro invocation | help: the type constructed contains `ParseIntError` due to the type of the argument passed --> src/bin/main_73960cf9c502217fe914332a7bf49e44b6dcf3f2.rs:5:18 | 5 | Err(e) => return Err(e), | ^^^^-^ | | | this argument influences the type of `Err` ... 18 | Some(first_line) => try_!(first_line.parse::<i32>()), | -------------------------------- in this macro invocation note: tuple variant defined here --> /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/result.rs:536:5 = note: this error originates in the macro `try_` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0308`. error: could not compile `rust` (bin "main_73960cf9c502217fe914332a7bf49e44b6dcf3f2") due to 1 previous error
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(result) => result,
Err(e) => return Err(e),
}
}
}
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 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
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
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

Error handling

Error handling

Error handling

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: use of deprecated `try` macro --> src/bin/main_6e8bd794d8746044f0d9508e5969d0502d61225a.rs:9:20 | 9 | let mut deep = try!(File::open("deep_quotes.txt")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated help: you can use the `?` operator instead | 9 - let mut deep = try!(File::open("deep_quotes.txt")); 9 + let mut deep = File::open("deep_quotes.txt")?; | help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax | 9 | let mut deep = r#try!(File::open("deep_quotes.txt")); | ++ error: use of deprecated `try` macro --> src/bin/main_6e8bd794d8746044f0d9508e5969d0502d61225a.rs:10:20 | 10 | let mut wide = try!(File::open("wide_quotes.txt")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated help: you can use the `?` operator instead | 10 - let mut wide = try!(File::open("wide_quotes.txt")); 10 + let mut wide = File::open("wide_quotes.txt")?; | help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax | 10 | let mut wide = r#try!(File::open("wide_quotes.txt")); | ++ error: use of deprecated `try` macro --> src/bin/main_6e8bd794d8746044f0d9508e5969d0502d61225a.rs:13:5 | 13 | try!(deep.read_to_string(&mut contents)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated help: you can use the `?` operator instead | 13 - try!(deep.read_to_string(&mut contents)); 13 + deep.read_to_string(&mut contents)?; | help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax | 13 | r#try!(deep.read_to_string(&mut contents)); | ++ error: use of deprecated `try` macro --> src/bin/main_6e8bd794d8746044f0d9508e5969d0502d61225a.rs:14:5 | 14 | try!(wide.read_to_string(&mut contents)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated help: you can use the `?` operator instead | 14 - try!(wide.read_to_string(&mut contents)); 14 + wide.read_to_string(&mut contents)?; | help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax | 14 | r#try!(wide.read_to_string(&mut contents)); | ++ warning: unused import: `Read` --> src/bin/main_6e8bd794d8746044f0d9508e5969d0502d61225a.rs:1:21 | 1 | use std::io::{self, Read}; | ^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unused import: `std::fs::File` --> src/bin/main_6e8bd794d8746044f0d9508e5969d0502d61225a.rs:2:5 | 2 | use std::fs::File; | ^^^^^^^^^^^^^ error: could not compile `rust` (bin "main_6e8bd794d8746044f0d9508e5969d0502d61225a") due to 4 previous errors; 2 warnings emitted
use std::io::{self, Read};
use std::fs::File;
fn main() {}
fn all_your_quotes_are_belong_to_us() -> Result {
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 = 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)
}
use std::io::{self, Read};
use std::fs::File;
fn main() {}
fn all_your_quotes_are_belong_to_us() -> Result {
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 = 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;

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
});

Error handling

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

1 2 3 4 5 6
let number = "foo".parse::<i32>();
println!("{:?}", number);

let number = "foo".parse::<i32>()
    .map_err(|e| format!("еее, {} ли бе", e));
println!("{:?}", number);
Err(ParseIntError { kind: InvalidDigit }) Err("еее, invalid digit found in string ли бе")
fn main() {
let number = "foo".parse::();
println!("{:?}", number);

let number = "foo".parse::()
    .map_err(|e| format!("еее, {} ли бе", e));
println!("{:?}", number);
}

Error handling

Още по-лесно: с trait object

1 2 3 4 5 6 7 8 9 10 11
use std::error::Error;

fn all_your_numbers_are_belong_to_us() -> Result<i32, Box<dyn Error>> {
    let mut numbers = File::open("numbers.txt")?;
    // ...
    Ok(42)
}

fn main() {
    println!("{:?}", all_your_numbers_are_belong_to_us());
}
Err(Os { code: 2, kind: NotFound, message: "No such file or directory" })
use std::fs::File;
use std::error::Error;

fn all_your_numbers_are_belong_to_us() -> Result> {
    let mut numbers = File::open("numbers.txt")?;
    // ...
    Ok(42)
}

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

Error handling

Също толкова лесно и по-удобно: с anyhow!

1 2 3 4 5 6 7 8 9 10 11 12 13 14
// [dependencies]
// anyhow = "1.0"

use anyhow::anyhow;

fn all_your_numbers_are_belong_to_us() -> Result<i32, anyhow::Error> {
    let mut numbers = File::open("numbers.txt")?;
    // ...
    Err(anyhow!("No need for conversion"))
}

fn main() {
    println!("{:?}", all_your_numbers_are_belong_to_us());
}
Err(No such file or directory (os error 2))
use std::fs::File;
// [dependencies]
// anyhow = "1.0"

use anyhow::anyhow;

fn all_your_numbers_are_belong_to_us() -> Result {
    let mut numbers = File::open("numbers.txt")?;
    // ...
    Err(anyhow!("No need for conversion"))
}

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

Видове грешки

Грешките служат за две главни цели:

Видове грешки

Грешките служат за две главни цели:

Видове грешки

Грешките служат за две главни цели:

Видове грешки

Rust позполява различен подход за различните типове грешки:

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 се разделят на два вида

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

Въпроси