אופרטור סימן השאלה '?'
חלק מהיחידה לוגיקה וזרימת תוכנית במסלול ה-Rust של Coddy. שיעור 46 מתוך 66.
כשעובדים עם פונקציות שמחזירות Result, לעיתים קרובות צריך לטפל בשגיאות באופן מקומי או להעביר אותן לפונקציה הקוראת. Rust מספקת אופרטור אלגנטי לדפוס הנפוץ הזה: אופרטור סימן השאלה ?.
האופרטור ? מספק דרך נקייה להעביר שגיאות הלאה בלי לכתוב פקודות match ארוכות. כשמציבים ? אחרי Result, הוא שולף אוטומטית ערך Ok או מחזיר מיד מהפונקציה הנוכחית עם Err:
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // אם הפענוח נכשל, החזר את השגיאה
Ok(number * 2) // אם הפענוח הצליח, הכפל את המספר ב-2
}הדבר שקול לכתיבת משפט match מלא, אבל תמציתי הרבה יותר. אם s.parse::<i32>() מחזירה Ok, הסימן ? מחלץ את הערך ומשייך אותו אל number. אם היא מחזירה Err, הסימן ? מחזיר מיד את השגיאה הזו מכל הפונקציה.
שימו לב לתחביר ::<i32>. הוא נקרא turbofish, והוא מורה ל-Rust לאיזה טיפוס לנתח את המחרוזת. הפונקציה מחזירה Result<i32, std::num::ParseIntError>, כאשר i32 הוא טיפוס ההצלחה ו-std::num::ParseIntError הוא טיפוס השגיאה שמוחזר כאשר הניתוח נכשל.
אפשר להשתמש באופרטור ? רק בפונקציות שמחזירות Result (או Option), מכיוון שהוא צריך להיות מסוגל להחזיר שגיאה.
אתגר
קלתקבלו שתי קלטים. הקלט הראשון הוא מחרוזת שיש לנתח למספר שלם, והקלט השני הוא מחרוזת נוספת שגם אותה יש לנתח למספר שלם. צרו פונקציה בשם add_numbers שמקבלת שתי פרוסות מחרוזת כפרמטרים ומחזירה Result<i32, std::num::ParseIntError>. בתוך הפונקציה, השתמשו באופרטור ? כדי לנתח את שתי המחרוזות ולהחזיר את הסכום שלהן עטוף ב-Ok. קראו לפונקציה עם שני הקלטים וטפלו בתוצאה באמצעות match.
דרישות:
- קראו את הקלט הראשון (המספר הראשון כמחרוזת) והסירו רווחים מיותרים
- קראו את הקלט השני (המספר השני כמחרוזת) והסירו רווחים מיותרים
- צרו פונקציה
add_numbersשמקבלת שני פרמטרים מסוג&strומחזירהResult<i32, std::num::ParseIntError> - בתוך הפונקציה, נתחו את המחרוזת הראשונה ל-
i32באמצעות האופרטור? - נתחו את המחרוזת השנייה ל-
i32באמצעות האופרטור? - החזירו
Ok(sum)כאשר sum הוא סכום שני המספרים שנותחו - קראו לפונקציה עם שתי מחרוזות הקלט
- השתמשו בביטוי
matchכדי לטפל ב-Result - בזרוע
Ok(value), הדפיסו:Sum: [value] - בזרוע
Err(_), הדפיסו:Parsing error
קלט:
- שורה ראשונה: מחרוזת שמייצגת מספר (לדוגמה,
15) - שורה שנייה: מחרוזת שמייצגת מספר נוסף (לדוגמה,
27)
פלט:
- אם שתי המחרוזות מייצגות מספרים תקינים:
Sum: [result] - אם לא ניתן לנתח אחת מהמחרוזות או את שתיהן:
Parsing error
נסו בעצמכם
use std::io;
// TODO: צרו כאן את הפונקציה add_numbers
// עליה לקבל שני פרמטרים מסוג &str ולהחזיר Result<i32, std::num::ParseIntError>
fn main() {
// קראו את הקלט הראשון
let mut input1 = String::new();
io::stdin().read_line(&mut input1).expect("Failed to read line");
let input1 = input1.trim();
// קראו את הקלט השני
let mut input2 = String::new();
io::stdin().read_line(&mut input2).expect("Failed to read line");
let input2 = input2.trim();
// TODO: קראו ל-add_numbers עם input1 ו-input2
// TODO: השתמשו ב-match כדי לטפל ב-Result
// הדפיסו "Sum: [value]" עבור Ok(value)
// הדפיסו "Parsing error" עבור Err(_)
}השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה לוגיקה וזרימת תוכנית
1זרימת בקרה מתקדמת
ביטוי 'match'התאמה למספר ערכיםהתאמה לטווחיםביטוי 'if let'לולאות כביטוייםסיכום – מנתח פקודות פשוט4קיבוץ נתונים באמצעות מבנים
מהו מבנה?סקירה כללית על מבניםגישה לשדות במבנהמבנים הניתנים לשינוימבנים כפרמטרים של פונקציהמבני טופלסיכום – יצירת מבנה ספר7טיפול בשגיאות באמצעות 'Result'
מהו 'Result'?שימוש ב-'match' עם 'Result'is_ok() ו-is_err()קיצורי דרך: unwrap ו-expectאופרטור סימן השאלה '?'המרת מחרוזות למספריםסיכום - פונקציית חילוק בטוחה10Closures ופונקציות אנונימיות
מהו Closure?הגדרת Closure פשוטClosures עם פרמטריםלכידת הסביבהסיכום – Closure פשוט לחיבור2מבוא לווקטורים
מהו וקטור?יצירת וקטורהוספת איברים באמצעות pushגישה לאיברי וקטורמעבר על וקטורמעבר ניתן לשינויהסרת איבריםסיכום – מעקב בסיסי אחר ניקוד5זוגות מפתח-ערך באמצעות מפות גיבוב
מהי מפת גיבוב?יצירת מפת גיבובהוספת זוגות מפתח-ערךגישה לערכיםמעבר על מפת גיבובעדכון ערךהסרת זוגסיכום – מונה מיליםתרגלו בעצמכם: קומפיילר Rust אונליין