Справяне с грешки
11 ноември 2025
Конвертиране
From и Into
Два типажа, които ще ни трябват по-късно
Конвертиране
From
pub trait From<T> {
fn from(value: T) -> Self;
}
fn main() {}
pub trait From {
fn from(value: T) -> Self;
}
Конвертиране
From
pub trait From<T> {
fn from(value: T) -> Self;
}
fn main() {}
pub trait From {
fn from(value: T) -> Self;
}
impl From<T> for Uконвертира отTдоU
Конвертиране
From
pub trait From<T> {
fn from(value: T) -> Self;
}
fn main() {}
pub trait From {
fn from(value: T) -> Self;
}
impl From<T> for Uконвертира отTдоU- конвертирането не може да се провали (няма място за грешка в резултата)
Конвертиране
From
pub trait From<T> {
fn from(value: T) -> Self;
}
fn main() {}
pub trait From {
fn from(value: T) -> Self;
}
impl From<T> for Uконвертира отTдоU- конвертирането не може да се провали (няма място за грешка в резултата)
impl From<T> for Tе имплементирано автоматично (в стандартната библиотека)
Конвертиране
Into
- реципрочен метод
pub trait Into<T> {
fn into(self) -> T;
}
Конвертиране
Into
- реципрочен метод
pub trait Into<T> {
fn into(self) -> T;
}
impl Into<U> for Tконвертира отTдоU
Конвертиране
Into
- реципрочен метод
pub trait Into<T> {
fn into(self) -> T;
}
impl Into<U> for Tконвертира отTдоUInto<U> for Tсе имплементира автоматично когато имплементирамеFrom<T> for U
Конвертиране
Into
- реципрочен метод
pub trait Into<T> {
fn into(self) -> T;
}
impl Into<U> for Tконвертира отTдоUInto<U> for Tсе имплементира автоматично когато имплементирамеFrom<T> for U- практиката е ръчно да се имплементира
From
Конвертиране
Пример
// използва `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
- Ами ако искаме да конструираме стойност от низ? (от JSON низ, от XML, …)
String parsing
- Ами ако искаме да конструираме стойност от низ? (от JSON низ, от XML, …)
- Не можем да използваме
From, защото не сме сигурни че създаването ще е успешно
String parsing
- Ами ако искаме да конструираме стойност от низ? (от JSON низ, от XML, …)
- Не можем да използваме
From, защото не сме сигурни че създаването ще е успешно - Има специален типаж за това -
FromStr
String parsing
FromStr
trait FromStr {
type Err;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
enum Result<T, E> {
Ok(T),
Err(E),
}
- Конвертиране от низ до наш си тип
- Връща
Resultкойто показва дали конвертирането е успешно
String parsing
FromStr
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
И тук има реципрочен метод
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> { ... }
}
- Типа
<F as FromStr>::Errе "типаErr, който е дефиниран заFromStrимплементацията наF"
String parsing
parse
И тук има реципрочен метод
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> { ... }
}
- Типа
<F as FromStr>::Errе "типаErr, който е дефиниран заFromStrимплементацията наF" - Generic параметъра
Fтрябва да имплементираFromStr(подобно наIntoзаFrom)
String parsing
parse
И тук има реципрочен метод
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> { ... }
}
- Типа
<F as FromStr>::Errе "типаErr, който е дефиниран заFromStrимплементацията наF" - Generic параметъра
Fтрябва да имплементираFromStr(подобно наIntoзаFrom) - Метода
parseе имплементиран върхуstr
String parsing
parse
И тук има реципрочен метод
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> { ... }
}
- Типа
<F as FromStr>::Errе "типаErr, който е дефиниран заFromStrимплементацията наF" - Generic параметъра
Fтрябва да имплементираFromStr(подобно наIntoзаFrom) - Метода
parseе имплементиран върхуstr - Метода
parseе generic по return стойността си
String parsing
parse
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
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
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
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
use std::str::FromStr;
#[derive(Debug)]
struct Student {
name: String,
faculty_number: String,
}
String parsing
parse
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
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
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 връща информация защо конвертирането е било неуспешно
impl FromStr for i32 {
type Err = ParseIntError;
fn from_str(src: &str) -> Result<Self, ParseIntError> {
...
}
}
String parsing
невъзможни грешки
Но какво да върнем, ако конвертирането е винаги успешно?
impl FromStr for String {
type Err = ???;
fn from_str(s: &str) -> Result<String, Self::Err> {
Ok(String::from(s))
}
}
String parsing
невъзможни грешки
Можем да върнем (), защото нямаме информация за грешка ..
impl FromStr for String {
type Err = ();
fn from_str(s: &str) -> Result<String, Self::Err> {
Ok(String::from(s))
}
}
String parsing
невъзможни грешки
.. но има по-добър вариант - Infallible
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?
enum Infallible {}
String parsing
невъзможни грешки
Какво е Infallible?
enum Infallible {}
- празен enum?
Празни типове
На типовете можем да гледаме като на множества от стойности
bool = { true, false }
u32 = { 0, 1, ..., 2**32-1 }
Празните структури са типове с точно една възможна стойност - нула бита информация
() = { () }
struct Empty;
Empty = { Empty }
Празни типове
Празните енуми са типове с нула възможни стойности - празното множество.
enum Never {}
Never = { }
Стойност от тип Never не може да съжествува в програмата
Празни типове
Това значи, че парче код, което съдържа стойност от тип Never никога не би се изпълнило
let x: Never = some_expression();
something_else();
// за компилатора е еквиваленто на
some_expression();
// unreachable!!
// something_else();
String parsing
невъзможни грешки
Това е удобно, когато искаме да изразим невъзможна грешка
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
невъзможни грешки
Защото компилатора може да види, че единия ръкав е недостижим
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
невъзможни грешки
Защото компилатора може да види, че единия ръкав е недостижим
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:?}");
}
}
}
- това всъщност е ново от rust 1.82
https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#omitting-empty-types-in-pattern-matching
String parsing
невъзможни грешки
Това също е позволено
let Ok(s) = "some text".parse::<String>();
fn main() {
let Ok(s) = "some text".parse::();
}
Never type
- rust има вграден "never" тип -
!
pub fn exit(code: i32) -> !
Never type
- rust има вграден "never" тип -
!
pub fn exit(code: i32) -> !
- но той не е стабилизан все още
Never type
- rust има вграден "never" тип -
!
pub fn exit(code: i32) -> !
- но той не е стабилизан все още
- затова на негово място се използва празен енум като
enum Never {}
Never type
Изрази, които имат стойност от тип !
// безкраен цикъл без break в тялото
loop {}
panic!()
todo!()
unreachable!()`
std::process::exit()
// и други
Never type
Стойност от тип ! може да се конвертира до произволен друг тип
Never type
Стойност от тип ! може да се конвертира до произволен друг тип
- (защото празното множество е подмножество на всяко множесто)
Never type
Стойност от тип ! може да се конвертира до произволен друг тип
- (защото празното множество е подмножество на всяко множесто)
- (т.е.
!е подтип на всеки тип)
Never type
Стойност от тип ! може да се конвертира до произволен друг тип
- (защото празното множество е подмножество на всяко множесто)
- (т.е.
!е подтип на всеки тип)
Това позволява код като:
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
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
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
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
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
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
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
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
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
macro_rules! try_ {
($expr:expr) => {
match $expr {
Ok(result) => result,
Err(e) => return Err(e),
}
}
}
Error handling
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?
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?
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?
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
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
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
#[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
Сега можем и да си разширим малко помощното макро
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
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
- израза
return Err(e.into());изглежда по един и същ начин какъвто и да е конкретния return тип.
Error handling
- израза
return Err(e.into());изглежда по един и същ начин какъвто и да е конкретния return тип. - и затова
try_!е глобално използваем - и съществува в стандартната библиотека като
try!
Error handling
- израза
return Err(e.into());изглежда по един и същ начин какъвто и да е конкретния return тип. - и затова
try_!е глобално използваем - и съществува в стандартната библиотека като
try! - (използваме
try_!вместоtry!в слайдовете, защотоtryе запазена дума 😅)
Error handling
try! използва твърде много скоби и удивителни. И е deprecated.
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
Има по-прост синтаксис: ?
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
(Има и по-прост метод за четене на файлове)
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
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
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
if let Err(_) = some_side_effects() {
// Едно warning-че, да се знае...
}
Error handling
методи върху Result
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
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);
}
- Ако не ни се занимава с conversion методи
Видове грешки
Грешките служат за две главни цели:
Видове грешки
Грешките служат за две главни цели:
- error handling
- показват, че дадена операция е била неуспешна
- съдържат информация програмата да реши какво следващо действие да предприеме.
Видове грешки
Грешките служат за две главни цели:
- error handling
- показват, че дадена операция е била неуспешна
- съдържат информация програмата да реши какво следващо действие да предприеме.
- error reporting
- генерират съобщение за грешка
- което се показва на потребител или се записва в лог файл
- трябва да са разбираеми от човек
- служат за разследване какво се е случило със системата посфактум
Видове грешки
Грешките трябва да съдържат:
- error handling
- типове, стойности
- използват се когато пишем библиотечен код
Видове грешки
Грешките трябва да съдържат:
- error handling
- типове, стойности
- използват се когато пишем библиотечен код
- error reporting
- текст - съобщение за грешка
- използват се когато пишем приложение
Видове грешки
В Rust за error handling стандартно използваме enum-и.
Този пример работи, но не ни дава всичката информация
#[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)
}
}
Видове грешки
По-добър вариант би било
#[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
cargo add thiserror
// Cargo.toml
[dependencies]
thiserror = "2.0.17"
Видове грешки
Пакета thiserror предоставя derive macro thiserror::Error
Което автоматично генерира имплементации за:
- From
- Display
- std::error::Error
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),
}
Видове грешки
Използване
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
- типаж, който се използва за error reporting
- съобщението за грешка е в имплементацията на
std::fmt::Display - т.е.
println!("{}", e)
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
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!
// [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!("something terrible happened")
Panic
Виждали сме panic:
panic!("something terrible happened")assert_eq!(1, 2)
Panic
Виждали сме panic:
panic!("something terrible happened")assert_eq!(1, 2)None.unwrap()
Panic
Какво прави паниката
Panic
Какво прави паниката
- работи на ниво нишки
Panic
Какво прави паниката
- работи на ниво нишки
- терминира нишката в която е извикана и изписва съобщение за грешка
Panic
Какво прави паниката
- работи на ниво нишки
- терминира нишката в която е извикана и изписва съобщение за грешка
- unwind-ва стека (по подразбиране, може да се променя при компилация)
Panic
Какво прави паниката
- работи на ниво нишки
- терминира нишката в която е извикана и изписва съобщение за грешка
- unwind-ва стека (по подразбиране, може да се променя при компилация)
- при паника в главната нишка се прекратява цялата програма
Panic
Какво прави паниката
- работи на ниво нишки
- терминира нишката в която е извикана и изписва съобщение за грешка
- unwind-ва стека (по подразбиране, може да се променя при компилация)
- при паника в главната нишка се прекратява цялата програма
- паниките не е предвидено да бъдат хващани (няма catch)
Panic
Какво прави паниката
- работи на ниво нишки
- терминира нишката в която е извикана и изписва съобщение за грешка
- unwind-ва стека (по подразбиране, може да се променя при компилация)
- при паника в главната нишка се прекратява цялата програма
- паниките не е предвидено да бъдат хващани (няма catch)
- (има
catch_unwind, но това е за специални случаи)
Panic
Кога?
Panic
Кога?
- грешки в логиката на програмата
- (или при използване на библиотека)
Panic
Кога?
- грешки в логиката на програмата
- (или при използване на библиотека)
- които не зависят от user input
- и няма смисъл да се опитаме да се възстановим от тях
Panic
Кога?
- грешки в логиката на програмата
- (или при използване на библиотека)
- които не зависят от user input
- и няма смисъл да се опитаме да се възстановим от тях
"-13".parse::<u32>().unwrap()
Panic
Кога?
- грешки в логиката на програмата
- (или при използване на библиотека)
- които не зависят от user input
- и няма смисъл да се опитаме да се възстановим от тях
"-13".parse::<u32>().unwrap()io::stdin().parse::<u32>()-> любезно съобщение "please try again, but better"
Panic
Кога?
- грешки в логиката на програмата
- (или при използване на библиотека)
- които не зависят от user input
- и няма смисъл да се опитаме да се възстановим от тях
"-13".parse::<u32>().unwrap()io::stdin().parse::<u32>()-> любезно съобщение "please try again, but better"while let Err(_) = io::stdin().parse::<u32>() { ... }
Panic
Кога?
- грешки в логиката на програмата
- (или при използване на библиотека)
- които не зависят от user input
- и няма смисъл да се опитаме да се възстановим от тях
"-13".parse::<u32>().unwrap()io::stdin().parse::<u32>()-> любезно съобщение "please try again, but better"while let Err(_) = io::stdin().parse::<u32>() { ... }
- тестове
- примери
- rapid prototyping
Error handling
Обобщение
Грешките в rust се разделят на два вида
Error handling
Обобщение
Грешките в rust се разделят на два вида
- такива от които можем да се възстановим -
Result,Option, etc
Error handling
Обобщение
Грешките в rust се разделят на два вида
- такива от които можем да се възстановим -
Result,Option, etc - такива от които не можем да се възстановим -
panic!
Error handling
Обобщение
Грешките в rust се разделят на два вида
- такива от които можем да се възстановим -
Result,Option, etc - такива от които не можем да се възстановим -
panic! unreachable!(),todo!()са от втория тип
Error handling
Обобщение
Грешките в rust се разделят на два вида
- такива от които можем да се възстановим -
Result,Option, etc - такива от които не можем да се възстановим -
panic! unreachable!(),todo!()са от втория тип- няма exceptions!