عامل علامة الاستفهام '?'
جزء من قسم المنطق وتدفّق التنفيذ في رحلة Rust على Coddy. الدرس 46 من 66.
عند العمل مع الدوال التي تُرجع Result، غالبًا ما تحتاج إلى handle الأخطاء إما بالتعامل معها محليًا أو بتمريرها إلى الدالة المستدعِية. توفّر Rust معاملًا أنيقًا لهذا النمط الشائع: معامل علامة الاستفهام ?.
يوفّر العامل ? طريقة واضحة لتمرير الأخطاء دون كتابة عبارات match مطوّلة. عند وضع ? بعد Result، فإنه يفك تلقائيًا قيمة Ok أو يعيد التنفيذ فورًا من الدالة الحالية مع Err:
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // إذا فشل التحليل، أعد الخطأ
Ok(number * 2) // إذا نجح، ضاعف الرقم
}هذا يعادل كتابة عبارة match كاملة، لكنه أكثر اختصارًا بكثير. إذا أعاد s.parse::<i32>() قيمة Ok، فإن ? يستخرج القيمة ويُسنِدها إلى number. وإذا أعاد قيمة Err، فإن ? يعيد ذلك الخطأ فورًا من كامل function.
لاحظ صيغة ::<i32>. تُسمّى هذه الصيغة turbofish، وهي تخبر Rust بالنوع الذي يجب تحليل السلسلة النصية إليه. تُرجع الدالة Result<i32, std::num::ParseIntError>، حيث إن i32 هو نوع النجاح، وstd::num::ParseIntError هو نوع الخطأ الذي يتم إرجاعه عند فشل parsing.
لا يمكن استخدام المعامل ? إلا في الدوال التي تُرجع Result (أو Option)، لأنه يحتاج إلى أن يتمكن من إرجاع خطأ.
التحدي
سهلستتلقى مدخلين. المدخل first هو سلسلة نصية ينبغي تحليلها إلى عدد صحيح، والمدخل second هو سلسلة نصية أخرى ينبغي أيضًا تحليلها إلى عدد صحيح. أنشئ دالة تُسمى add_numbers تتلقى شريحتي نص كـ parameters وتُرجع قيمة من النوع Result<i32, std::num::ParseIntError>. داخل الدالة، استخدم عامل ? لتحليل السلسلتين وإرجاع مجموعهما مغلفًا داخل Ok. استدعِ الدالة باستخدام المدخلين وتعامل مع result باستخدام match.
المتطلبات:
- اقرأ المدخل
first(العددfirstكسلسلة نصية) وأزل المسافات البيضاء - اقرأ المدخل
second(العددsecondكسلسلة نصية) وأزل المسافات البيضاء - أنشئ دالة
add_numbersتتلقى اثنين من&strكـparametersوتُرجعResult<i32, std::num::ParseIntError> - داخل الدالة، حلّل السلسلة
firstإلىi32باستخدام عامل? - حلّل السلسلة
secondإلىi32باستخدام عامل? - أرجع
Ok(sum)حيث إن sum هو جمع العددين اللذين تم تحليلهما - استدعِ الدالة باستخدام سلسلتي الإدخال
- استخدم تعبير
matchللتعامل معResult - في ذراع
Ok(value)، اطبع:Sum: [value] - في ذراع
Err(_)، اطبع:Parsing error
المدخل:
- السطر
first: سلسلة نصية تمثل عددًا (مثلًا:15) - السطر
second: سلسلة نصية تمثل عددًا آخر (مثلًا: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)
// Print "Parsing error" for Err(_)
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس المنطق وتدفّق التنفيذ
1تدفق التحكم المتقدم
تعبير 'match'مطابقة قيم متعددةمطابقة النطاقاتتعبير 'if let'الحلقات التكرارية كتعبيراتمراجعة - محلل أوامر بسيط4تجميع البيانات باستخدام Structs
ما هو الـ Struct؟نظرة عامة على الـ Structsالوصول إلى حقول الـ Structالـ Structs القابلة للتعديلالـ Structs كمعاملات للدوالالـ Tuple Structsمراجعة - إنشاء Book Struct7معالجة الأخطاء باستخدام 'Result'
ما هو 'Result'؟استخدام 'match' مع 'Result'is_ok() و is_err()اختصارات: unwrap و expectعامل علامة الاستفهام '?'تحويل السلاسل النصية إلى أرقامملخص - دالة القسمة الآمنة10الـ Closures والدوال المجهولة
ما هو الـ Closure؟تعريف Closure بسيطالـ Closures مع المعاملاتالتقاط البيئة المحيطةملخص - Closure الجامع البسيط2مقدمة في الـ Vectors
ما هو الـ Vector؟إنشاء Vectorإضافة عناصر باستخدام pushالوصول إلى عناصر الـ Vectorالتكرار عبر الـ Vectorالتكرار القابل للتعديل (Mutable Iteration)إزالة العناصرمراجعة - متتبع نقاط بسيط5أزواج (المفتاح والقيمة) مع Hash Maps
ما هو Hash Map؟إنشاء Hash Mapإدراج أزواج (المفتاح والقيمة)الوصول إلى القيمالتكرار عبر Hash Mapتحديث قيمةإزالة زوجملخص - عداد الكلمات6التعامل مع غياب القيم باستخدام 'Option'
ما هو الـ 'Option'؟استخدام 'match' مع 'Option''is_some()' و 'is_none()'فك تغليف الـ 'Option'الدالة 'expect'توفير قيمة افتراضية: 'unwrap_or'مراجعة - البحث عن عنصر9شرائح الـ String والمزيد
String مقابل &strإنشاء شرائح الـ Stringالشرائح كمعاملات للدوالشرائح أخرىمراجعة - إيجاد الكلمة الأولىتدرّب بنفسك: مترجم Rust عبر الإنترنت