Rust学习笔记
Rust编程语言入门教程课程笔记
参考教材: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community)
Lecture 9: Error Handling
use std::error::Error;
use std::io::ErrorKind;
use std::fs::File;
use std::io::Read;
use std::net::IpAddr;
use std::io;fn main() -> Result<(), Box<dyn Error>> {//Box<dyn Error> means the function will return a type that implements the Error trait// Rust groups errors into two major categories: recoverable and unrecoverable errors.// For a recoverable error, such as a file not found error, it’s reasonable to report// the problem to the user and retry the operation. Unrecoverable errors are always// symptoms of bugs, like trying to access a location beyond the end of an array.// Recoverable errors are instances of the Result<T, E> enum, which has variants// Ok(T), representing success and containing a value, and Err(E), representing error// and containing an error value. The Result<T, E> enum is defined as part of the// standard library.// The panic! macro can be used to generate a panic and start unwinding its stack.// While unwinding, the runtime will take care of freeing all the resources owned by// the thread by calling the destructors of all its objects.let f = File::open("hello.txt");match f {Ok(file) => file,Err(error) => panic!("Problem opening the file: {:?}", error),};let _f = File::open("hello.txt").unwrap();//unwrap returns the Ok value inside the Ok variant//unwrap cannot define the type of the error so it will panic if it is Errlet _f = File::open("hello.txt").expect("Failed to open hello.txt");//expect is similar to unwrap but it allows us to choose the panic message//matching on different errorslet f = File::open("hello.txt");let _f = match f {Ok(file) => file,Err(error) => match error.kind() {ErrorKind::NotFound => match File::create("hello.txt") {Ok(fc) => fc,Err(error) => panic!("Problem creating the file: {:?}", error),},other_error => panic!("Problem opening the file: {:?}", other_error),},};let _f = File::open("hello.txt").unwrap_or_else(|error| {//unwrap_or_else takes a closureif error.kind() == ErrorKind::NotFound {File::create("hello.txt").unwrap_or_else(|error| {panic!("Problem creating the file: {:?}", error);})} else {panic!("Problem opening the file: {:?}", error);}});//propagating errorslet _ = read_username_from_file();//shortcut for propagating errors: the ? operatorlet _ = _read_username_from_file();//the ? operator can only be used in functions that return Result//translating errors from one type into another using From trait//when implementing the From trait, the standard library provides a generic//implementation of From<T> for any type T that implements the Into<U> trait//this is useful when we want to return a specific error type but the function//we are calling returns a generic error type//panic! vs Resultlet _home: IpAddr = "127.0.0.1".parse().expect("Hardcoded IP address should be valid");//create a custom type for the errorlet guess = Guess::new(99);//the constructor will check if the value is validprintln!("Guess value: {}", guess.value());//use ? in mainlet _greeting_file = File::open("hello.txt")?;Ok(()) //fn main() -> Result<(), Box<dyn Error>>
}fn read_username_from_file() -> Result<String, io::Error> {let f = File::open("hello.txt");let mut f = match f {Ok(file) => file,Err(e) => return Err(e),//early return};let mut s = String::new();match f.read_to_string(&mut s) {Ok(_) => Ok(s),Err(e) => Err(e),//early return}
}pub struct Guess {value: i32,
}impl Guess {pub fn new(value: i32) -> Guess {if value < 1 || value > 100 {panic!("Guess value must be between 1 and 100, got {}.", value);}Guess { value }}pub fn value(&self) -> i32 {//we need to return a reference to the valueself.value}
}fn _read_username_from_file() -> Result<String, io::Error> {let mut f = File::open("hello.txt")?;//? can only be used in functions that return Resultlet mut s = String::new();f.read_to_string(&mut s)?;//? can only be used in functions that return ResultOk(s)
} //? can be chained to simplify the code