Result
Ta có thể thấy rằng enum Option
có thể được dùng như là giá trị trả về từ các hàm có thể có lỗi,
trong đó None
có thể được dùng để trả về để biểu thị rằng có lỗi xảy ra. Tuy nhiên đôi khi việc diễn tả tại sao
một thao tác bị lỗi lại quan trọng hơn. Để làm được điều này, ta đã có enum Result
.
Enum Result<T, E>
có hai biến thể:
Ok(value)
để biểu thị một thao tác đã thành công và kèm theo đó làvalue
được trả về bởi thao tác đó. (value
có kiểuT
)Err(why)
để biểu thị một thao tác đã thất bại và kèm theo đó làwhy
, thứ được kì vọng để giải thích nguyên nhân gây nên lỗi. (why
có kiểuE
)
mod checked { // "Các lỗi" toán học mà chúng ta muốn bắt #[derive(Debug)] pub enum MathError { DivisionByZero, NonPositiveLogarithm, NegativeSquareRoot, } pub type MathResult = Result<f64, MathError>; pub fn div(x: f64, y: f64) -> MathResult { if y == 0.0 { // Thao tác này sẽ `thất bại`, thay vào đó hãy trả về nguyên nhân của // sự thất bại được gói bên trong `Err` Err(MathError::DivisionByZero) } else { // Thao tác này là hợp lệ, trả về kết quả được gói bên trong `Ok` Ok(x / y) } } pub fn sqrt(x: f64) -> MathResult { if x < 0.0 { Err(MathError::NegativeSquareRoot) } else { Ok(x.sqrt()) } } pub fn ln(x: f64) -> MathResult { if x <= 0.0 { Err(MathError::NonPositiveLogarithm) } else { Ok(x.ln()) } } } // `op(x, y)` === `sqrt(ln(x / y))` fn op(x: f64, y: f64) -> f64 { // Dưới đây là ba tầng match lồng nhau! match checked::div(x, y) { Err(why) => panic!("{:?}", why), Ok(ratio) => match checked::ln(ratio) { Err(why) => panic!("{:?}", why), Ok(ln) => match checked::sqrt(ln) { Err(why) => panic!("{:?}", why), Ok(sqrt) => sqrt, }, }, } } fn main() { // Liệu thao tác có thất bại không? println!("{}", op(1.0, 10.0)); }