Lesson 2 — Error Handling
🎯 Learning Objectives
- Hiểu cơ chế error handling trong Rust bằng
Result<T, E>. - Biết cách dùng
match/unwrap/expect, và đặc biệt?operator.
🔑 Key Concepts & Glossary
Result<T, E> là một enum có hai biến thể:
Ok(T)đại diện cho giá trị hợp lệ.Err(E)đại diện cho lỗi.
expr? tương đương với:
- Nếu
exprlàOk(v)→ trả vềv. - Nếu
exprlàErr(e)→ returnErr(e)ngay lập tức.
Rust khuyến khích propagate lỗi an toàn thay vì nuốt lỗi hay throw exception. Điều này giúp code predict được control flow và compiler kiểm soát tốt hơn.
Các thuật ngữ quan trọng:
- Result<T, E>: Enum để biểu diễn kết quả thành công hoặc lỗi.
- ? operator: Shortcut để propagate lỗi lên caller.
- unwrap / expect: Trích giá trị từ
Result, panic nếu làErr. - Propagate: Truyền lỗi lên caller thay vì xử lý ngay.
💻 Example Implementation
Cargo.toml
[package]
name = "lesson02_error_handling"
version = "0.1.0"
edition = "2024"
src/main.rs
use std::fs; use std::io; use std::env; fn main() -> Result<(), io::Error> { // Read env var with fallback let filename = env::var("APP_FILE").unwrap_or_else(|_| "hello.txt".to_string()); // Use helper function that returns Result let content = read_file(&filename)?; println!("File {filename} says: {content}"); Ok(()) } fn read_file(path: &str) -> Result<String, io::Error> { let data = fs::read_to_string(path)?; // propagate error if the file does not exist Ok(data) }
Nếu file
hello.txtkhông tồn tại → chương trình trả vềErrthay vì crash.
🛠️ Hands-on Exercises
- Basic: Viết hàm
parse_number(s: &str) -> Result<i32, std::num::ParseIntError>để parse string thành số. - Intermediate: Kết hợp đọc file + parse số từ file, trả về tổng của tất cả số nguyên trong đó.
- Challenge: Viết CLI nhỏ nhận tên file từ
std::env::args(), đọc toàn bộ nội dung và in ra số ký tự. Xử lý lỗi file không tồn tại bằng?.
🐞 Common Pitfalls & Debugging Tips
- Dùng
.unwrap()hoặc.expect()bừa bãi → dễ panic khi lỗi. - Quên propagate lỗi bằng
?, khiến code rối vớimatch. - Trộn lẫn nhiều loại error mà không convert (
Fromtrait).
🔄 Migration Notes (Rust 2024+)
?operator đã stable từ Rust 1.13 → an toàn để dùng.- Nên chuyển từ
try!()macro cũ sang?. - Rust 2024 không có breaking change về error handling, chỉ cải thiện ergonomic khi dùng
?trong closure và async.
❓ Q&A — Common Questions
Q1. Vì sao Rust không có exceptions?
- Vì Rust muốn control flow minh bạch: lỗi là giá trị (
Result), không có jump ẩn. Nhờ đó code dễ dự đoán, hiệu năng tốt hơn, an toàn hơn.
Q2. Result<T, E> khác Option<T> thế nào?
Option<T>: có hoặc không, không lý do.Result<T, E>: thành công hoặc lỗi kèm lý do. → DùngOptionkhi “vắng mặt” là bình thường,Resultkhi cần thông tin lỗi.
Q3. Khi nào dùng ?, khi nào dùng match?
?: khi chỉ muốn propagate lỗi nguyên trạng.match: khi cần xử lý tại chỗ (retry, fallback, đổi lỗi, log thêm context).
📚 References
🌿 Wisdom Note
Thiên lý chi hành, thủy vu túc hạ.
A journey of a thousand miles begins beneath one’s feet.
Xử lý lỗi cũng như đi đường dài: đi từng bước nhỏ, propagate từng lỗi đúng chỗ. Không cần “nhảy vọt” (exceptions), mà giữ flow tự nhiên, an toàn.