blog.dopana

Back

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

Hã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),
}
rust

Bạ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:?}"),
    };
}
rust

Cách viết tắt: unwrapexpect#

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");
rust

Nê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(())
}
rust

Nế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!

Tài liệu tham khảo#