Xử lý lỗi trong Rust
Học cách xử lý lỗi không thể phục hồi với panic!, xử lý lỗi có thể phục hồi với Result<T, E>, và lan truyền lỗi bằng toán tử ?.
Bài thứ mười trong loạt Rust cơ bản. Rust chia lỗi thành hai nhóm chính: lỗi không thể phục hồi sử dụng panic! và lỗi có thể phục hồi sử dụng Result<T, E>.
Lỗi không thể phục hồi với panic!#
Khi chương trình gặp một điều kiện nghiêm trọng không thể tiếp tục (như truy cập mảng vượt quá chỉ số), Rust gọi macro panic!. Macro này in ra thông báo lỗi, tháo dỡ bộ nhớ (unwind stack) và thoát tiến trình:
fn main() {
// panic!("gặp sự cố nghiêm trọng");
let v = vec![1, 2, 3];
// v[99]; // tự động panic
}rustHãy sử dụng panic! khi xuất hiện trạng thái không hợp lệ mà chương trình của bạn không thể tự khắc phục.
Lỗi có thể phục hồi với Result#
Đối với các thao tác có thể thất bại một cách dự đoán được (như mở một file hoặc parse số nguyên), các hàm sẽ trả về Result<T, E>:
enum Result<T, E> {
Ok(T),
Err(E),
}rustBạn kiểm tra Result bằng match:
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!("Sự cố khi mở file: {error:?}"),
};
}rustCách viết tắt: unwrap và expect#
Result cung cấp các phương thức tiện lợi để lấy giá trị T hoặc panic nếu gặp Err:
let file = File::open("hello.txt").unwrap();
let file = File::open("hello.txt").expect("File hello.txt phải tồn tại trong thư mục này");rustNên ưu tiên dùng expect thay vì unwrap trong code thực tế vì nó cung cấp thông tin ngữ cảnh hữu ích khi log sự cố.
Lan truyền lỗi với ?#
Khi viết hàm, bạn thường muốn chuyển lỗi lên cho nơi gọi hàm xử lý thay vì giải quyết ngay lập tức. Toán tử ? mang lại cú pháp ngắn gọn để lan truyền lỗi:
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username = String::new();
File::open("hello.txt")?.read_to_string(&mut username)?;
Ok(username)
}
fn main() -> Result<(), io::Error> {
let username = read_username_from_file()?;
println!("Tên người dùng: {username}");
Ok(())
}rustNếu biểu thức được đánh giá bởi ? trả về Err, giá trị Err đó sẽ lập tức được trả về từ hàm chứa nó.
Kết luận#
Rust làm cho việc xử lý lỗi trở nên tường minh: panic! dành cho các thất bại nghiêm trọng, Result<T, E> quản lý lỗi phục hồi được, và ? hỗ trợ lan truyền lỗi gọn gàng. Bài viết này khép lại loạt 10 bài Rust cơ bản!