Bài học theo mô-đun (2/2)
Xử lý lỗi và ? Toán tử
Triết lý của Rust khuyến khích bạn nhận ra khả năng xảy ra lỗi một cách rõ ràng và cấu trúc mã của bạn để xử lý chúng trước khi chương trình được biên dịch.
Lỗi trong Rust được chia thành hai loại chính: lỗi không thể khôi phục (gây ra sự chấm dứt ngay lập tức thông qua macro panic!) và lỗi có thể khôi phục (được quản lý bằng loại Result<T, E>).
Kết quả<T, E> Loại và kết hợp mẫu
Hầu hết các lỗi có thể phục hồi đều trả về loại Result<T, E>, là một enum được định nghĩa là:
enum Result<T, E> {
Ok(T),
Err(E),
}Chúng ta có thể sử dụng khớp mẫu để kiểm tra kết quả:
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}Tuyên truyền lỗi với toán tử ?
Khi triển khai một hàm, thay vì xử lý lỗi trực tiếp bên trong nó, chúng ta thường muốn trả lại lỗi cho người gọi để họ có thể quyết định phải làm gì. Quá trình này được gọi là lan truyền lỗi.
Rust cung cấp toán tử ? như một lối tắt cú pháp để truyền lỗi. Nếu giá trị của Result là Ok thì giá trị bên trong của Ok sẽ được biểu thức trả về; nếu là Err thì lỗi Err sẽ được trả về từ toàn bộ hàm hiện tại như thể chúng ta đã sử dụng return Err(...).
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("username.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}[! QUAN TRỌNG] Chỉ có thể sử dụng toán tử
?trong các hàm trả về loại tương thích với giá trị được áp dụng (thường làResult,Optionhoặc các loại triển khaiFromResidual).
Lỗi tùy chỉnh
Chúng tôi có thể xác định các loại lỗi tùy chỉnh của riêng mình bằng cách triển khai đặc điểm std::fmt::Display (và tùy chọn std::error::Error) để cung cấp cách trình bày lỗi mà con người có thể đọc được:
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {}", self.details)
}
}
impl std::error::Error for MyError {}Hãy tự mình thử
Bài tập 1: Đọc file có đuôi ? toán tử
Hoàn thành hàm read_username_from_file để nó sử dụng ? toán tử để truyền các lỗi được tạo bằng cách mở tệp và đọc nội dung của nó vào chuỗi tên người dùng.
Hiển thị gợi ý
Thêm `?`ký tự sau`File::open(...)`và after`username_file.read_to_string(...)` để truyền lỗi.
Giải pháp khả dụng sau 3 lần thử
Bài tập 2: Phân tích và nhân đôi một số
Viết hàm có tên là parse_and_double chấp nhận tham chiếu chuỗi &str và trả về Kết quả<i32, std::num::ParseIntError>. Hàm sẽ phân tích chuỗi bằng cách sử dụng val.parse::<i32>() với ? để truyền các lỗi phân tích cú pháp và khi thành công sẽ trả về giá trị nhân đôi được gói trong Ok.
Hiển thị gợi ý
Sử dụng `val.parse::<i32>()?`để phân tích chuỗi và truyền lỗi, sau đó return`Ok(num \* 2)`.
Giải pháp khả dụng sau 3 lần thử
Bài tập 3: Xác định lỗi tùy chỉnh
Xác định cấu trúc trống có tên CustomError. Triển khai đặc điểm std::fmt::Display cho nó bằng cách viết 'Si e verificato un errore Personalizzato' làm thông báo lỗi trong phương thức fmt.
Hiển thị gợi ý
Khai báo `struct CustomError;`và triển khai Hiển thị bằng cách viết`write!(f, "Si e verificato un errore Personalizzato")`bên trong phương thức`fmt`.
Giải pháp khả dụng sau 3 lần thử