وسائط الدالة الافتراضية في Rust: حلول أنيقة بدون تحميل زائد

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا لا توجد وسائط افتراضية في Rust - وكيفية تجاوز ذلك

\n\n

إذا أتيت إلى Rust من Python أو JavaScript أو C++، فمن المحتمل أنك واجهت مفاجأة: في Rust لا يوجد دعم مدمج للوسائط الافتراضية. لا يمكنك ببساطة كتابة fn greet(name = "عالم") - سيخبرك المترجم "لا".

\n\n

لكن لا تتعجل في الإحباط! يقدم Rust طرقًا أخرى أكثر مرونة وأمانًا. في هذا البرنامج التعليمي، سنشرح 3 طرق مثبتة لتنفيذ سلوك الوسائط الافتراضية. ستتعلم كيفية استخدام Option<T>، والهياكل مع الإعدادات، ونمط Builder - وأي طريقة تختار لمهمتك.

\n\n

المقالة مبنية على سؤال حقيقي من Stack Overflow (أكثر من 50,000 مشاهدة) - قمنا بتكييفه للصيغة التعليمية. هيا بنا!

\n\n

الطريقة 1. استخدام Option<T> - الخيار الأبسط

\n\n

الطريقة الأكثر مباشرة هي استقبال الوسائط كـ Option<T> واستبدال القيم الافتراضية داخل الدالة.

\n\n
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

السلبيات:

\n
    \n
  • كل استدعاء يتطلب تغليفًا في Some(...) أو None
  • \n
  • إذا كان هناك عدة معاملات - يصبح الكود ضخمًا
  • \n
\n\n

هذا النهج مناسب تمامًا للدوال ذات 1-2 معاملات اختيارية. ولكن إذا كان هناك المزيد - تتأثر قابلية القراءة.

\n\n

الطريقة 2. هيكل مع إعدادات - نظيف وقابل للتوسع

\n\n

عندما تصبح المعاملات 3 أو 5 أو 10، يأتي للإنقاذ هيكل التكوين. تقوم بإنشاء نوع منفصل يخزن جميع الإعدادات، وتنفذ له trait Default.

\n\n
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
    \n
  • تتطلب كودًا تمهيديًا أكثر
  • \n
  • تحتاج إلى تنفيذ trait Default بشكل صريح
  • \n
\n\n

هذا هو الخيار المثالي للمشاريع الحقيقية: المكتبات، دوال التكوين، واجهات API المعقدة.

\n\n

الطريقة 3. نمط Builder - لمن يحبون السلاسل

\n\n

نمط Builder هو كلاسيكي في نظام Rust البيئي. تقوم بإنشاء هيكل باني يقوم بتجميع المعاملات، وفي النهاية يستدعي طريقة build().

\n\n
struct Greeter {\n    name: String,\n    greeting: String,\n    excitement_level: u8,\n}\n\nstruct GreeterBuilder {\n    nam                

المدونات

توصيات الكتب