لماذا لا توجد وسائط افتراضية في Rust - وكيفية تجاوز ذلك
\n\nإذا أتيت إلى Rust من Python أو JavaScript أو C++، فمن المحتمل أنك واجهت مفاجأة: في Rust لا يوجد دعم مدمج للوسائط الافتراضية. لا يمكنك ببساطة كتابة fn greet(name = "عالم") - سيخبرك المترجم "لا".
لكن لا تتعجل في الإحباط! يقدم Rust طرقًا أخرى أكثر مرونة وأمانًا. في هذا البرنامج التعليمي، سنشرح 3 طرق مثبتة لتنفيذ سلوك الوسائط الافتراضية. ستتعلم كيفية استخدام Option<T>، والهياكل مع الإعدادات، ونمط Builder - وأي طريقة تختار لمهمتك.
المقالة مبنية على سؤال حقيقي من Stack Overflow (أكثر من 50,000 مشاهدة) - قمنا بتكييفه للصيغة التعليمية. هيا بنا!
\n\nالطريقة 1. استخدام Option<T> - الخيار الأبسط
\n\nالطريقة الأكثر مباشرة هي استقبال الوسائط كـ Option<T> واستبدال القيم الافتراضية داخل الدالة.
fn greet(name: Option<&str>) {\n let name = name.unwrap_or("عالم");\n println!("مرحبًا، {}!", name);\n}\n\nfn main() {\n greet(Some("آنا")); // مرحبًا، آنا!\n greet(None); // مرحبًا، عالم!\n}\n\n\nالإيجابيات:
\n- \n
- أقل كود \n
- واضح حتى للمبتدئين \n
- لا يتطلب هياكل إضافية \n
السلبيات:
\n- \n
- كل استدعاء يتطلب تغليفًا في
Some(...)أوNone\n - إذا كان هناك عدة معاملات - يصبح الكود ضخمًا \n
هذا النهج مناسب تمامًا للدوال ذات 1-2 معاملات اختيارية. ولكن إذا كان هناك المزيد - تتأثر قابلية القراءة.
\n\nالطريقة 2. هيكل مع إعدادات - نظيف وقابل للتوسع
\n\nعندما تصبح المعاملات 3 أو 5 أو 10، يأتي للإنقاذ هيكل التكوين. تقوم بإنشاء نوع منفصل يخزن جميع الإعدادات، وتنفذ له trait Default.
struct GreetConfig {\n name: String,\n greeting: String,\n excitement_level: u8,\n}\n\nimpl Default for GreetConfig {\n fn default() -> Self {\n Self {\n name: "عالم".to_string(),\n greeting: "مرحبًا".to_string(),\n excitement_level: 1,\n }\n }\n}\n\nfn greet(config: GreetConfig) {\n let excitement = "!".repeat(config.excitement_level as usize);\n println!("{}, {}{}", config.greeting, config.name, excitement);\n}\n\nfn main() {\n // استخدام القيم الافتراضية\n greet(GreetConfig::default());\n // الإخراج: مرحبًا، عالم!\n\n // تغيير ما نحتاجه فقط\n greet(GreetConfig {\n name: "آنا".to_string(),\n ..Default::default()\n });\n // الإخراج: مرحبًا، آنا!\n\n // استدعاء مخصص بالكامل\n greet(GreetConfig {\n name: "عالم".to_string(),\n greeting: "أهلاً".to_string(),\n excitement_level: 3,\n });\n // الإخراج: أهلاً، عالم!!!\n}\n\n\nالإيجابيات:
\n- \n
- أقصى مرونة \n
- يمكن إضافة حقول جديدة بدون تغيير توقيع الدالة \n
- صياغة
..Default::default()قابلة للقراءة جدًا \n
السلبيات:
\n- \n
- تتطلب كودًا تمهيديًا أكثر \n
- تحتاج إلى تنفيذ trait
Defaultبشكل صريح \n
هذا هو الخيار المثالي للمشاريع الحقيقية: المكتبات، دوال التكوين، واجهات API المعقدة.
\n\nالطريقة 3. نمط Builder - لمن يحبون السلاسل
\n\nنمط Builder هو كلاسيكي في نظام Rust البيئي. تقوم بإنشاء هيكل باني يقوم بتجميع المعاملات، وفي النهاية يستدعي طريقة build().
struct Greeter {\n name: String,\n greeting: String,\n excitement_level: u8,\n}\n\nstruct GreeterBuilder {\n nam