ראסט - פונקציית main נקיה יותר עם Result
כחלק מהמסע שלנו לניהול שגיאות נכון נפל לנו האסימון שלהשתמש ב unwrap או expect יכול להיות רעיון לא כל כך טוב ועלול להביא לסיום מיידי של הפרוסס שלנו במקרים שאולי לא התכוונו אליהם.

כחלק מהמסע שלנו לניהול שגיאות נכון נפל לנו האסימון שלהשתמש ב unwrap או expect יכול להיות רעיון לא כל כך טוב ועלול להביא לסיום מיידי של הפרוסס שלנו במקרים שאולי לא התכוונו אליהם. אז השתמשנו ב clippy deny unwrap used שגרם לקומפילציה לא לעבור במידה ונכנס unwrap לקוד.
המקום היחיד בו היינו צריכים להשאיר unwrap היה בסט הוולידציות ההתחלתי בעליה של הפרוסס שלנו, בפונקציית ה main. לדוגמה - בניסיון למשוך את הקונפיגורציה הראשונית בעליה - אם נכשלנו מסיבה כלשהי נהרוג את הפרוסס.
לימים פונקציית ה main הכילה יותר ויותר ולידציות כאלה ובנוסף גם התחלנו להרוג את הפרוסס שלנו כחלק מתהליך פונקציונאלי תקין במקרים מסויימים (exit code).
בפוסט אנסה להציג את האלטרנטיבה שבחרנו לטיפול בשגיאות ב main באמצעות unwrap
איך נראה main סטנדרטי
use std::fs::File;
use std::io::Read;
fn main() {
// Read the configuration file, expecting it to succeed
let config = read_config("config.toml").expect("Failed to read config");
// Process the data, unwrapping the result
process_data(&config).expect("Failed to process data");
}
fn read_config(filename: &str) -> infra::Result<String> {
let mut file = File::open(filename)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn process_data(config: &str) -> infra::Result<()> {
// Simulate data processing
if config.contains("error") {
Err("Simulated processing error".into())
} else {
println!("Data processed successfully.");
Ok(())
}
}
הפריע לי בעין לראות כל כך הרבה unwrap וחיפשתי דרך נקייה יותר לנהל את השגיאות שעלולות לצוץ ב main. באחת מעשרות השיחות הטכניות שלי על ראסט עם המנטור שלי, הוא העלה את האופציה פשוט להחזיר result מפונקציית ה main וככה אם תוחזר שגיאה ב main היא תפועפע שכבה אחת והתכנית תסגר עם אותה הודעת השגיאה (ממש עם unwrap).
main שמחזיר result
fn main() -> infra::Result<()> {
// Read the configuration file
let config = read_config("config.toml")?;
// Process the data
process_data(&config)?;
Ok(())
}
דבר קטן נוסף - main לא חייב להחזיר “()” או unit בהגה המקצועית. במקרים בהם הפרוסס שלנו יכול לצאת במגוון exit codes שונים, נוכל להגדיר ש main יחזיר std::process::ExitCode .
fn main() -> infra::Result<ExitCode> {
// Read the configuration file
let config = read_config("config.toml")?;
// Process the data
let exit_code = process_data(&config)?;
Ok(exit_code)
}
סיכום
קריאות ל unwrap מתוך פונקציית ה main הן לא דבר שגוי כאשר אנחנו באמת רוצים לקרוס בהינתן שגיאה. הפוסט מציע דרך אלטרנטיבית שאני מצאתי ״נקייה״ יותר - החזרת Result מפונקציית ה main ואפשרות לפעפע שגיאות באמצעות ? כמו שאנחנו רגילים לראות בפונקציות הרגילות שלנו.