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

11 ноември 2025

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

From и Into

Два типажа, които ще ни трябват по-късно

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

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

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

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

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

Пример

1 2 3 4 5
// използва `impl From<&str> for String`
let s1 = String::from("hello");

// използва `impl Into<String> for &str`
let s2: String = "hello".into();
fn main() {
// използва `impl From<&str> for String`
let s1 = String::from("hello");

// използва `impl Into for &str`
let s2: String = "hello".into();
}

String parsing

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_once(",") {
            Some((name, faculty_number)) => {
                let name = name.trim().to_string();
                let faculty_number = faculty_number.trim().to_string();

                Ok(Self { name, faculty_number })
            },
            None => Err(String::from("🤷🤷🤷")),
        }
    }
}
fn main() {}
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_once(",") {
            Some((name, faculty_number)) => {
                let name = name.trim().to_string();
                let faculty_number = faculty_number.trim().to_string();

                Ok(Self { name, faculty_number })
            },
            None => 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_once(",") {
Some((name, faculty_number)) => {
let name = name.trim().to_string();
let faculty_number = faculty_number.trim().to_string();
Ok(Self { name, faculty_number })
},
None => 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_once(",") {
Some((name, faculty_number)) => {
let name = name.trim().to_string();
let faculty_number = faculty_number.trim().to_string();
Ok(Self { name, faculty_number })
},
None => 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!("it's {s:?}");
    }
    Err(_) => { // Err(Infallible)
        println!("this code is, actually, unreachable");
    }
}
it's "some string"
fn main() {
match "some string".parse::() {
    Ok(s) => {  // Ok(String)
        println!("it's {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!("it's {s:?}");
    }
}
it's "some string"
fn main() {
match "some string".parse::() {
    Ok(s) => {
        println!("it's {s:?}");
    }
}
}

String parsing

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

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

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

String parsing

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

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

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

Never type

1
pub fn exit(code: i32) -> !

Never type

1
pub fn exit(code: i32) -> !

Never type

1
pub fn exit(code: i32) -> !

Never type

Изрази, които имат стойност от тип !

1 2 3 4 5 6 7 8 9 10
// безкраен цикъл без break в тялото
loop {}

panic!()
todo!()
unreachable!()`

std::process::exit()

// и други

Never type

Стойност от тип ! може да се конвертира до произволен друг тип

Never type

Стойност от тип ! може да се конвертира до произволен друг тип

Never type

Стойност от тип ! може да се конвертира до произволен друг тип

Never type

Стойност от тип ! може да се конвертира до произволен друг тип

Това позволява код като:

1 2 3 4
let a: i32 = 10;
let b: i32 = todo!();

println!("sum is {}", a + b);
#![allow(unreachable_code)]
fn main() {
let a: i32 = 10;
let b: i32 = todo!();

println!("sum is {}", a + b);
}

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, std::io::Error>` | note: the method `read_to_string` exists on the type `File` --> /home/nikola/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/mod.rs:991:5 | 991 | fn read_to_string(&mut self, buf: &mut String) -> Result<usize> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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); | +++++++++++++++++ For more information about this error, try `rustc --explain E0599`. error: could not compile `rust` (bin "main_c656429131e242e34ce39a654c1457567c9b5847") due to 1 previous error
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
impl File {
    pub fn open(path: P) -> Result<File, io::Error>
    where
        P: AsRef<Path>
}

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

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

Error handling

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

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

    let mut result = vec![];
    for line in contents.lines() {
        let n = try_!(line.parse::<i32>());
        result.push(n);
    };

    Ok(result)
}

fn main() {
    println!("{:?}", all_your_numbers_are_belong_to_us());
}
error[E0308]: mismatched types --> src/bin/main_40c907ae8a583104993691e429dae5db7e2b27cf.rs:5:22 | 5 | Err(e) => return Err(e), | --- ^ expected `Error`, found `ParseIntError` | | | arguments to this enum variant are incorrect ... 19 | let n = try_!(line.parse::<i32>()); | -------------------------- in this macro invocation | help: the type constructed contains `ParseIntError` due to the type of the argument passed --> src/bin/main_40c907ae8a583104993691e429dae5db7e2b27cf.rs:5:18 | 5 | Err(e) => return Err(e), | ^^^^-^ | | | this argument influences the type of `Err` ... 19 | let n = try_!(line.parse::<i32>()); | -------------------------- in this macro invocation note: tuple variant defined here --> /home/nikola/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:557:5 | 557 | Err(#[stable(feature = "rust1", since = "1.0.0")] E), | ^^^ = 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_40c907ae8a583104993691e429dae5db7e2b27cf") 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, io::Error> {
    let mut numbers = try_!(File::open("numbers.txt"));

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

    let mut result = vec![];
    for line in contents.lines() {
        let n = try_!(line.parse::());
        result.push(n);
    };

    Ok(result)
}

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 14 15 16 17
#[derive(Debug)]
enum FancyError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

impl From<io::Error> for FancyError {
    fn from(e: io::Error) -> Self {
        FancyError::Io(e)
    }
}

impl From<num::ParseIntError> for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError::Parse(e)
    }
}
use std::{io, num};
fn main() {
#[derive(Debug)]
enum FancyError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

impl From for FancyError {
    fn from(e: io::Error) -> Self {
        FancyError::Io(e)
    }
}

impl From for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError::Parse(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),        // old
            Err(e) => return Err(e.into()), // new
        }
    }

}

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<Vec<i32>, FancyError> {
    let mut numbers = try_!(File::open("numbers.txt"));

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

    let mut result = vec![];
    for line in contents.lines() {
        let n = try_!(line.parse::<i32>());
        result.push(n);
    };

    Ok(result)
}
Ok([65, 21, 32, 19, 43])
use std::fs::File;
use std::io::Read;
use std::{io, num};
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(n) => n,
Err(e) => return Err(e.into()),
}
}
}
#[derive(Debug)]
enum FancyError {
Io(io::Error),
Parse(num::ParseIntError),
}
impl From for FancyError {
fn from(e: io::Error) -> Self {
FancyError::Io(e)
}
}
impl From for FancyError {
fn from(e: num::ParseIntError) -> Self {
FancyError::Parse(e)
}
}
fn main() {
let file_contents = "65\n21\n32\n19\n43\n";
std::fs::write("numbers.txt", file_contents.as_bytes()).unwrap();
fn all_your_numbers_are_belong_to_us() -> Result, FancyError> {
    let mut numbers = try_!(File::open("numbers.txt"));

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

    let mut result = vec![];
    for line in contents.lines() {
        let n = try_!(line.parse::());
        result.push(n);
    };

    Ok(result)
}

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

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

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

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

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

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

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

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

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

Грешките трябва да съдържат:

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

Грешките трябва да съдържат:

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

В Rust за error handling стандартно използваме enum-и.

Този пример работи, но не ни дава всичката информация

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#[derive(Debug)]
enum FancyError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

impl From<io::Error> for FancyError {
    fn from(e: io::Error) -> Self {
        FancyError::Io(e)
    }
}

impl From<num::ParseIntError> for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError::Parse(e)
    }
}
fn main() {}
use std::{io, num};
#[derive(Debug)]
enum FancyError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

impl From for FancyError {
    fn from(e: io::Error) -> Self {
        FancyError::Io(e)
    }
}

impl From for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError::Parse(e)
    }
}

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

По-добър вариант би било

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#[derive(Debug)]
enum FancyError {
    FileOpenError { file: String, err: io::Error },
    ReadError(io::Error),
    ParseError(num::ParseIntError),
}

impl From<num::ParseIntError> for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError::ParseError(e)
    }
}

impl Display for FancyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            FancyError::FileOpenError{file, err} => write!(f, "failed opening file {:?}: {}", file, err),
            FancyError::ReadError(err) => write!(f, "failed reading file contents: {}", err),
            FancyError::ParseError(err) => write!(f, "failed parsing: {}", err),
        }
    }
}
fn main() {}
use std::{io, num, fmt};
use std::fmt::Display;
#[derive(Debug)]
enum FancyError {
    FileOpenError { file: String, err: io::Error },
    ReadError(io::Error),
    ParseError(num::ParseIntError),
}

impl From for FancyError {
    fn from(e: num::ParseIntError) -> Self {
        FancyError::ParseError(e)
    }
}

impl Display for FancyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            FancyError::FileOpenError{file, err} => write!(f, "failed opening file {:?}: {}", file, err),
            FancyError::ReadError(err) => write!(f, "failed reading file contents: {}", err),
            FancyError::ParseError(err) => write!(f, "failed parsing: {}", err),
        }
    }
}

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

Това е малко boilerplate - има външен пакет, който улеснява нещата
https://docs.rs/thiserror

1
cargo add thiserror
1 2 3
// Cargo.toml
[dependencies]
thiserror = "2.0.17"

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

Пакета thiserror предоставя derive macro thiserror::Error
Което автоматично генерира имплементации за:

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

#[derive(Error, Debug)]
enum FancyError {
    #[error("failed opening file {file:?}: {err}")]
    FileOpenError { file: String, err: io::Error },
    #[error("failed reading file contents: {0}")]
    ReadError(io::Error),
    #[error("failed parsing: {0}")]
    ParseError(#[from] num::ParseIntError),
}
fn main() {}
use std::{io, num};
use thiserror::Error;

#[derive(Error, Debug)]
enum FancyError {
    #[error("failed opening file {file:?}: {err}")]
    FileOpenError { file: String, err: io::Error },
    #[error("failed reading file contents: {0}")]
    ReadError(io::Error),
    #[error("failed parsing: {0}")]
    ParseError(#[from] num::ParseIntError),
}

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

Използване

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<Vec<i32>, FancyError> {
    let mut numbers = File::open("numbers.txt")
        .map_err(|err| FancyError::FileOpenError { file: "numbers.txt".into(), err })?;

    let mut contents = String::new();
    numbers.read_to_string(&mut contents)
        .map_err(FancyError::ReadError)?;

    let mut result = vec![];
    for line in contents.lines() {
        let n = line.parse::<i32>()?;
        result.push(n);
    };

    Ok(result)
}
fn main() {}
use std::{io, num};
use std::fs::File;
use std::io::Read;
use thiserror::Error;
#[derive(Error, Debug)]
enum FancyError {
#[error("failed opening file {file:?}: {err}")]
FileOpenError { file: String, err: io::Error },
#[error("failed reading file contents: {0}")]
ReadError(io::Error),
#[error("failed parsing: {0}")]
ParseError(#[from] num::ParseIntError),
}
fn all_your_numbers_are_belong_to_us() -> Result, FancyError> {
    let mut numbers = File::open("numbers.txt")
        .map_err(|err| FancyError::FileOpenError { file: "numbers.txt".into(), err })?;

    let mut contents = String::new();
    numbers.read_to_string(&mut contents)
        .map_err(FancyError::ReadError)?;

    let mut result = vec![];
    for line in contents.lines() {
        let n = line.parse::()?;
        result.push(n);
    };

    Ok(result)
}

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

trait std::error::Error

1 2 3 4 5 6 7 8 9 10
pub trait Error: Debug + Display {
    fn source(&self) -> Option<&(dyn Error + 'static)> { ... }

    // deprecated
    // fn description(&self) -> &str { ... }
    // fn cause(&self) -> Option<&dyn Error> { ... }

    // weird one
    // fn provide<'a>(&'a self, request: &mut Request<'a>) { ... }
}

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

trait std::error::Error

Използване - вече нямаме нужда от enum FancyError

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
use std::error::Error;

fn all_your_numbers_are_belong_to_us() -> Result<Vec<i32>, Box<dyn Error>> {
    let mut numbers = File::open("numbers.txt")
        .map_err(|e| format!("failed to open file {:?}: {}", "numbers.txt", e))?;

    let mut contents = String::new();
    numbers
        .read_to_string(&mut contents)
        .map_err(|e| format!("read failed: {}", e))?;

    let mut result = vec![];
    for line in contents.lines() {
        let n = line
            .parse::<i32>()
            .map_err(|e| format!("failed to parse as int: {}", e))?;

        result.push(n);
    }

    Ok(result)
}
fn main() {}
use std::fs::File;
use std::io::Read;
use std::error::Error;

fn all_your_numbers_are_belong_to_us() -> Result, Box> {
    let mut numbers = File::open("numbers.txt")
        .map_err(|e| format!("failed to open file {:?}: {}", "numbers.txt", e))?;

    let mut contents = String::new();
    numbers
        .read_to_string(&mut contents)
        .map_err(|e| format!("read failed: {}", e))?;

    let mut result = vec![];
    for line in contents.lines() {
        let n = line
            .parse::()
            .map_err(|e| format!("failed to parse as int: {}", e))?;

        result.push(n);
    }

    Ok(result)
}

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

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

https://docs.rs/anyhow

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// [dependencies]
// anyhow = "1.0"

use anyhow::{anyhow, Context};

fn all_your_numbers_are_belong_to_us() -> Result<Vec<i32>, anyhow::Error> {
    let mut numbers = File::open("numbers.txt")
        .with_context(|| format!("failed to open file {:?}", "numbers.txt"))?;

    let mut contents = String::new();
    numbers
        .read_to_string(&mut contents)
        .context("read failed")?;

    let mut result = vec![];
    for line in contents.lines() {
        match line.parse::<i32>() {
            Ok(n) => result.push(n),
            Err(e) => return Err(anyhow!("failed to parse {:?}: {}", line, e)),
        }
    }

    Ok(result)
}
fn main() {}
use std::fs::File;
use std::io::Read;
// [dependencies]
// anyhow = "1.0"

use anyhow::{anyhow, Context};

fn all_your_numbers_are_belong_to_us() -> Result, anyhow::Error> {
    let mut numbers = File::open("numbers.txt")
        .with_context(|| format!("failed to open file {:?}", "numbers.txt"))?;

    let mut contents = String::new();
    numbers
        .read_to_string(&mut contents)
        .context("read failed")?;

    let mut result = vec![];
    for line in contents.lines() {
        match line.parse::() {
            Ok(n) => result.push(n),
            Err(e) => return Err(anyhow!("failed to parse {:?}: {}", line, e)),
        }
    }

    Ok(result)
}

Panic

Panic

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

Panic

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

Въпроси