Result
Tương tự như Option
.
Một kết quả trả về (Result
)
của một function thường sẽ có hai trường hợp:
Result
là một phiên bản cao cấp hơn của Option
.
Nó mô tả lỗi gì đang xảy ra thay vì khả năng tồn tại giá trị hay không.
#![allow(unused)] fn main() { enum Result<T, E> { Ok(T), Err(E), } }
Ví dụ
fn get_id_from_name(name: &str) -> Result<i32, &str> { if !name.starts_with('d') { return Err("not found"); } Ok(123) } fn main() -> Result<(), &'static str> { let name = "duyet"; match get_id_from_name(name) { Ok(id) => println!("User = {}", id), Err(e) => println!("Error: {}", e), }; Ok(()) }
Như bạn thấy thì main()
cũng có thể return về Result<(), &'static str>
.unwrap()
Ví dụ trên nhưng sử dụng .unwrap()
, chủ động panic (crash) dừng chương trình nếu gặp lỗi.
fn main() -> Result<(), &'static str> { let who = "duyet"; let age = get_age(who).unwrap(); println!("{} is {}", who, age); Ok(()) }
.expect()
Giống như unwrap()
: chủ động panic (crash) dừng chương trình nếu gặp lỗi và kèm theo message. Sẽ rất có ích, nhất là khi có quá nhiều unwrap, bạn sẽ không biết nó panic ở đâu.
fn main() -> Result<(), &'static str> { let who = "ngan"; let age = get_age(who).expect("could not get age"); println!("{} is {}", who, age); Ok(()) }
Xem thêm mọi method khác của Result
tại đây.
Convert Result
-> Option
Đôi khi bạn sẽ cần convert từ:
Ok(v)
-->Some(v)
- hoặc ngược lại,
Err(e)
-->Some(e)
.ok()
// .ok(v) = Some(v) let x: Result<u32, &str> = Ok(2); assert_eq!(x.ok(), Some(2)); let y: Result<u32, &str> = Err("Nothing here"); assert_eq!(y.ok(), None);
.err()
// .err() let x: Result<u32, &str> = Ok(2); assert_eq!(x.err(), None); let x: Result<u32, &str> = Err("Nothing here"); assert_eq!(x.err(), Some("Nothing here"));
Toán tử ?
Khi viết code mà có quá nhiều functions trả về Result
, việc handle Err
sẽ khá nhàm chán.
Toán tử chấm hỏi ?
cho phép dừng function tại vị trí đó và return cho function cha nếu Result
ở vị trí đó là Err
.
Nó sẽ thay thế đoạn code sau:
#![allow(unused)] fn main() { use std::fs::File; use std::io::prelude::*; use std::io; struct Info { name: String, age: i32, rating: i32, } fn write_info(info: &Info) -> io::Result<()> { // Early return on error let mut file = match File::create("my_best_friends.txt") { Err(e) => return Err(e), Ok(f) => f, }; if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) { return Err(e) } if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) { return Err(e) } if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) { return Err(e) } Ok(()) } }
thành
#![allow(unused)] fn main() { use std::fs::File; use std::io::prelude::*; use std::io; struct Info { name: String, age: i32, rating: i32, } fn write_info(info: &Info) -> io::Result<()> { let mut file = File::create("my_best_friends.txt")?; // Early return on error file.write_all(format!("name: {}\n", info.name).as_bytes())?; file.write_all(format!("age: {}\n", info.age).as_bytes())?; file.write_all(format!("rating: {}\n", info.rating).as_bytes())?; Ok(()) } }
Gọn đẹp hơn rất nhiều.
Toán tử ?
sẽ unwrap giá trị Ok
, hoặc return giá trị Err
ở vị trí gần toán tử đó.
?
chỉ có thể được dùng trong function có kiểu dữ liệu trả về là Result
.