Bạn có nhiều cách để sửa lỗi trong Rust. Bài viết sẽ tổng hợp cho bạn tất cả những phương pháp hiệu quả nhất để khắc phục lỗi trong Rust.
Khi lập trình web hay phát triển phần mềm, lỗi là không thể tránh khỏi và có thể xảy ra vì nhiều lí do, từ việc nhập sai dữ liệu tới gián đoạn mạng, trục trặc phần cứng… Xử lý lỗi là quá trình phát triển, báo cáo và khôi phục hệ thống bị lỗi để ngăn chặn sự cố chương trình hoặc hỏng dữ liệu.
Xử lý lỗi hiệu quả rất quan trọng trong Rust. Nó cho phép bạn tạo ra những ứng dụng mạnh mẽ, đáng tin cậy để xử lý những sự cố bất ngờ. Cơ chế xử lý lỗi của Rust cho phép bạn phát triển chương trình an toàn, linh hoạt và dễ bảo trì hơn.
Các kiểu lỗi trong Rust
Rust có một hệ thống kiểu phong phú mà bạn có thể dùng để xử lý lỗi thành thạo tùy theo kiểu của chúng. Không thể phủ nhận ưu điểm của hệ thống loại lỗi so với các phương pháp xử lý lỗi truyền thống. Hệ thống phân loại lỗi cung cấp kiểu an toàn, cải thiện khả năng kết hợp, tính biểu cảm và gỡ lỗi.
Dưới đây là danh sách kiểu lỗi phổ biến trong Rust:
- std::io::Error đại diện cho lỗi I/O, chẳng hạn như không thể tìm thấy file, quyền truy cập bị từ chối hoặc đã tới cuối tệp.
- std::num::ParseIntError đại diện cho lỗi xảy ra trong quá trình phân tích chuỗi tới số nguyên.
- std::option::NoneError đại diện cho lỗi trong quá trình mở rộng Options trống.
- std::result::Result<T, E> là một kiểu kết quả chung mà bạn có thể dùng để biểu thị lỗi bất kỳ.
Mỗi kiểu lỗi có phương pháp và đặc điểm riêng để xử lý nó theo cách cụ thể.
Dưới đây là một ví dụ về cách xử lý lỗi ở một hoạt động đọc file trong Rust:
use std::fs::File;
use std::io::Read;
fn read_file(path: &str) -> Result<String, std::io::Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
Hàm read_file đọc nội dung của tập tin ở đường dẫn được chỉ định và trả nó về dưới dạng chuỗi. Nó trả về std::io::Error nếu hoạt động mở hoặc đọc file thất bại. Toán tử ?
lan truyền lỗi và trả về lỗi dưới dạng Result.
Cơ chế xử lý lỗi trong Rust
Tính năng chính đóng góp vào sự an toàn của Rust là cơ chế xử lý lỗi. Hiện có 4 cơ chế sửa lỗi trong Rust: Result, Option, macro panic!, Error.
Kiểu Result và Option cho phép xử lý lỗi theo cấu trúc. Bạn có thể dùng macro panic! để xử lý lỗi không thể khôi phục. Đặc điểm Error cho phép bạn xác định các kiểu và xử lý lỗi tùy biến.
Kiểu Result
Result là một kiểu có sẵn đại diện cho kết quả hoạt động của một kiểu có thể thất bại. Nó có hai biến: Ok là thành công và chứa một giá trị, Err là thất bại và chứa một giá trị lỗi.
Dưới đây là cách bạn có thể dùng kiểu Result để mở một file và đọc nội dung của nó:
use std::fs::File;
use std::io::prelude::*;
fn read_file(file_path: &str) -> Result<String, std::io::Error> {
let mut file = File::open(file_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() {
let result = read_file("file.txt");
match result {
Ok(contents) => println!("{}", contents),
Err(e) => println!("Error: {}", e),
}
}
Hàm read_file lấy đường dẫn file và trả về lỗi Result<String, std::io::Error>. Nếu hoạt động đọc hay mở file thất bại, hàm trả về giá trị Err. Nếu không, hàm trả về giá trị Ok. Ở hàm main, lệnh match xử lý giá trị Result và in kết quả phụ thuộc vào tình huống của hoạt động file.
Kiểu Option
Option là một kiểu có sẵn đại diện cho sự hiện diện hay vắng mặt của một giá trị. Option có hai biến thể. Some đại diện cho một giá trị, None đại diện cho sự vắng mặt của một giá trị.
Dưới đây là cách bạn có thể dùng kiểu Option để lấy thành phần đầu tiên của một vector.
fn get_first_element<T: Clone>(vec: Vec<T>) -> Option<T> {
if vec.is_empty() {
None
} else {
Some(vec.first().unwrap().clone())
}
}
fn main() {
let vec = vec![1, 2, 3];
let result = get_first_element(vec);
match result {
Some(element) => println!("{}", element),
None => println!("The vector is empty."),
}
}
Hàm get_first_element trả về kiểu Option<T>. Nếu vector trống, hàm trả về None. Ngược lại, hàm trả về Some chứa thành phần đầu tiên của vector. Trong hàm main, lệnh match xử lý giá trị Option. Nếu Option đánh giá là Some, hàm in thành phần đầu tiên. Nếu không, hàm này xuất một thông báo cho biết vector trống.
Macro panic!
Macro panic! Cung cấp chức năng xử lý lỗi không thể khôi phục trong Rust. Khi gọi macro panic!, nó xuất một thông báo lỗi và kết thúc chương trình.
Dưới đây là một ví dụ về cách dùng macro panic! để chỉ báo hàm có các đối số không hợp lệ.
fn divide(dividend: f64, divisor: f64) -> f64 {
if divisor == 0.0 {
panic!("The divisor cannot be zero.");
}
dividend / divisor
}
fn main() {
let result = divide(4.0, 0.0);
println!("{}", result);
}
Hàm divide kiểm tra xem số chia có bằng 0. Nếu bằng 0, hàm này gọi macro panic! với một thông báo lỗi. Ngược lại, hàm divide tính toán, rồi trả về kết quả.
Hàm main gọi hàm chia với các đối số không hợp lệ để kích hoạt macro panic!.
Đây là thông báo lỗi:
Đặc tính Error
Error là một đặc tính có sẵn, xác định hành vi của các kiểu lỗi. Error cung cấp chức năng để xác định kiểu và xử lý lỗi tùy chỉnh.
Đây là ví dụ về cách xác định kiểu lỗi tùy biến. Đó là sự cố không tìm thấy file.
use std::error::Error;
use std::fmt;
use std::io::Read;
#[derive(Debug)]
struct FileNotFound(String);
impl fmt::Display for FileNotFound {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "File not found: {}", self.0)
}
}
impl Error for FileNotFound {}
fn read_file(file_path: &str) -> Result<String, Box<dyn Error>> {
let mut file = std::fs::File::open(file_path).map_err(|e| FileNotFound(format!("{}", e)))?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() {
let result = read_file("file.txt");
match result {
Ok(contents) => println!("{}", contents),
Err(e) => println!("Error: {}", e),
}
}
Kiểu lỗi tùy biến là struct FileNotFound. Kiểu này chứa một đường dẫn file. Kiểu FileNotFound triển khai đặc tính Display để trả về thông báo lỗi thân thiện người dùng và trait Error để cho biết đây là một kiểu lỗi.
Trong hàm read_file, kiểu lỗi FileNotFound đại diện cho lỗi không tìm thấy file. Phương thức map_err chuyển đổi std::io::Error thành FileNotFound. Cuối cùng, kiểu Box<dyn Error> cho phép hàm này trả về bất kỳ kiểu triển khai trait Error.
Hàm main gọi read_file với đường dẫn file. Nếu tìm thấy tập tin, xuất nội dung sang console. Nếu không, nó xuất thông báo lỗi.
Đây là kết quả cho một file không tồn tại:
Trên đây là những cách sửa lỗi thường gặp trong Rust. Hi vọng bài viết hữu ích với các bạn.