HashMap في Rust 2025: القيم الحرفية، الماكروات وأفضل الممارسات

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

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

ابدأ الدورة

إنشاء HashMap في Rust: من الألم إلى الجمال في عام 2025

\n\n

إذا كنت قد كتبت بلغة Rust من قبل وتساءلت "How do I create a HashMap literal?" — فأنت لست وحدك. هذا السؤال على Stack Overflow حصد آلاف المشاهدات، وليس بدون سبب. في لغات مثل Python أو JavaScript، إنشاء قاموس هو بضع أقواس معقوفة فقط. أما في Rust فالأمر أكثر تعقيدًا بعض الشيء… ولكن فقط للوهلة الأولى.

\n\n

في عام 2025، قطعت بيئة Rust شوطًا طويلاً. ظهرت ماكروات جديدة، وتحسن العمل مع الثوابت، وأصبح المترجم أكثر ذكاءً. في هذه المقالة، سنستعرض جميع طرق إنشاء HashMap، من الطرق الكلاسيكية إلى الأكثر حداثة. ستتعلم كيف تكتب كودًا ليس فقط عمليًا، بل جميلًا وفعالًا أيضًا.

\n\n

هيا بنا! 🦀

\n\n

لماذا لا يوجد قيمة حرفية مدمجة لـ HashMap في Rust؟

\n\n

هذا هو السؤال الأكثر شيوعًا من المبتدئين. الإجابة بسيطة: Rust ليست Python. لا يوجد "سحر" في Rust على مستوى بناء الجملة للمجموعات، لأن اللغة تسعى إلى قابلية التوقع والتحكم في الذاكرة.

\n\n

تخيل أنك تكتب:

\n\n
let map = {"key1": "value1", "key2": "value2"};
\n\n

يبدو منطقيًا؟ نعم. ولكن ماذا لو كانت المفاتيح أو القيم ليست نصوصًا، بل هياكل معقدة؟ كيف سيعرف المترجم أي مُخصص ذاكرة (allocator) يستخدم؟ وماذا عن التجزئة (hashing)؟ Rust يترك هذه القرارات للمطور.

\n\n

لهذا السبب، لإنشاء HashMap في المكتبة القياسية، يتم استخدام HashMap::new() والطرق .insert(). ولكن، اعترف بذلك، كتابة 10 أسطر من الكود لإنشاء قاموس من ثلاثة أزواج هو أمر مؤلم. لحسن الحظ، هناك حلول.

\n\n

الطريقة رقم 1: الكلاسيكية — HashMap::new() + insert()

\n\n

لنبدأ بالأساسيات. هذه هي الطريقة الأكثر وضوحًا وشفافية. تقوم بإنشاء HashMap فارغة ثم تملؤها:

\n\n
use std::collections::HashMap;\n\nfn main() {\n    let mut scores = HashMap::new();\n    scores.insert("Alice".to_string(), 42);\n    scores.insert("Bob".to_string(), 27);\n    scores.insert("Charlie".to_string(), 35);\n\n    println!("{:?}", scores);\n}
\n\n

الإيجابيات:

\n
    \n
  • تحكم كامل في العملية.
  • \n
  • يمكن إضافة عناصر بناءً على شرط.
  • \n
  • لا يتطلب تبعيات إضافية.
  • \n
\n\n

السلبيات:

\n
    \n
  • كثير الكلام (verbose).
  • \n
  • يتطلب mut.
  • \n
  • غير مناسب للثوابت.
  • \n
\n\n

هذه الطريقة جيدة للتعبئة الديناميكية، ولكن للبيانات الثابتة فهي مبالغ فيها.

\n\n

الطريقة رقم 2: from() — عندما تكون البيانات جاهزة

\n\n

إذا كان لديك متجه (vector) من الأزواج (tuples)، يمكنك استخدام HashMap::from():

\n\n
use std::collections::HashMap;\n\nfn main() {\n    let data = vec![\n        ("Alice", 42),\n        ("Bob", 27),\n        ("Charlie", 35),\n    ];\n\n    let scores: HashMap<&str, i32> = HashMap::from(data);\n    println!("{:?}", scores);\n}
\n\n

هذا أقرب إلى "القيمة الحرفية". يبدو أنظف، لكنه لا يزال يتطلب متجهًا وسيطًا. يعمل بسرعة، ولكن لمجموعات البيانات الكبيرة قد يكون غير فعال بسبب التخصيص المزدوج للذاكرة.

\n\n

الطريقة رقم 3: collect() — النهج الوظيفي

\n\n

سيعجب عشاق المُكررات (iterators) بهذه الطريقة:

\n\n
use std::collections::HashMap;\n\nfn main() {\n    let scores: HashMap<&str, i32> = [\n        ("Alice", 42),\n        ("Bob", 27),\n        ("Charlie", 35),\n    ].iter().cloned().collect();\n\n    println!("{:?}", scores);\n}
\n\n

جميل؟ نعم. قابل للقراءة؟ بصعوبة. لكنها واحدة من أكثر الطرق اصطلاحية (idiomatic) في Rust. .iter().cloned().collect() هو نمط قياسي لتحويل مصفوفة إلى مجموعة.

\n\n

بالمناسبة، إذا كانت مفاتيحك وقيمك تطبق الخاصية Copy، يمكنك استخدام .copied() بدلاً من .cloned() — وهذا أسرع قليلاً.

\n\n

الطريقة رقم 4: ماكرو hashmap! — المنقذ من عام 2025

\n\n

وهنا

المدونات

توصيات الكتب