مراجعة الكود في Rust: ما يجب التحقق منه وكيفية تقديم الملاحظات

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

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

ابدأ الدورة

مقدمة

Code review — جزء لا يتجزأ من التطوير الاحترافي. في نظام Rust البيئي، حيث تأتي سلامة الذاكرة والأداء في المقام الأول، يكتسب مراجعة الكود أهمية خاصة. الاستخدام غير الصحيح لـ unsafe، أو تجاهل قواعد الملكية (ownership)، أو حالات الذعر الضمنية يمكن أن تلغي جميع مزايا اللغة.

في هذه المقالة، سنناقش ما يجب التركيز عليه أثناء code review في Rust، وكيفية هيكلة الملاحظات، وما هي الأدوات التي يمكن أن تساعد في أتمتة الفحوصات. ستكون المادة مفيدة لكل من المبتدئين والمطورين ذوي الخبرة الذين يرغبون في تنظيم عملية المراجعة.



1. السلامة: فحص كود unsafe وحالات الذعر الضمنية

يضمن Rust سلامة الذاكرة، لكن unsafe هو تنازل عن هذه الضمانات. يجب فحص كل كتلة unsafe بدقة.



ما الذي يجب فحصه في كود unsafe؟

  • صحة المؤشرات: هل هناك إلغاء مرجعية لمؤشر فارغ أو متدلي.
  • محاذاة البيانات: هل المحاذاة صحيحة عند تحويل المؤشرات الخام.
  • التضارب (Aliasing): هل هناك انتهاكات لقواعد التضارب (مثل الاقتراض القابل للتغيير وغير القابل للتغيير في نفس الوقت).
  • الثوابت (Invariants): هل يتم الحفاظ على ثوابت هياكل البيانات (مثل بقاء الكومة الثنائية كومة).


// مثال سيء: تحويل غير آمن بدون التحقق من المحاذاةfn bad_unsafe(data: &[u8]) -> &[u32] {    unsafe {        std::slice::from_raw_parts(            data.as_ptr() as *const u32,            data.len() / 4        )    }}

// مثال جيد: مع التحقق من المحاذاةfn good_unsafe(data: &[u8]) -> Option<&[u32]> { if data.len() % 4 != 0 || data.as_ptr() as usize % 4 != 0 { return None; } Some(unsafe { std::slice::from_raw_parts( data.as_ptr() as *const u32, data.len() / 4 ) })}


حالات الذعر الضمنية

في Rust، هناك العديد من العمليات التي يمكن أن تسبب الذعر: unwrap()، expect()، panic!()، القسمة على صفر، الخروج عن حدود المصفوفة. في code review، يجب الانتباه إلى:

  • استخدم unwrap() فقط في الاختبارات أو عندما يكون الخطأ مستحيلاً حقًا.
  • فضل استخدام unwrap_or()، unwrap_or_else() أو المعالجة عبر match.
  • تحقق من أن جميع تحويلات as لا تفقد بيانات (مثل u64 as u32).


// سيء: ذعر ضمنيlet value = some_option.unwrap();

// جيد: معالجة صريحةlet value = some_option.unwrap_or_else(|| { log::error!("Missing expected value"); default_value()});


2. الملكية والاقتراض: الأخطاء النموذجية

نظام الملكية هو السمة الرئيسية لـ Rust. أخطاء المترجم هنا هي أفضل صديق، لكن code review يساعد في العثور على الأخطاء المنطقية التي لا يكتشفها المترجم.



الاستنساخ المفرط

مشكلة شائعة — الاستنساخ حيث يمكن تمرير مرجع. هذا يقلل الأداء ويزيد استخدام الذاكرة.



// سيء: استنساخ السلسلة بأكملهاfn process(data: Vec<String>) {    for item in data {        let cloned = item.clone();        do_something(&cloned);    }}

// جيد: تمرير مرجعfn process(data: &[String]) { for item in data { do_something(item); }}


الاقتراض غير الضروري و lifetime

تحقق مما إذا كان عمر المراجع طويلاً جدًا. في بعض الأحيان يمكن تبسيط توقيع الدالة عن طريق إزالة تعليقات lifetime الزائدة.



// معقد: lifetime زائدةfn longest<'a>(x: &'a str, y: &'a str) -> &'a str {    if x.len() > y.len() { x } else { y }}

// إذا

المدونات

توصيات الكتب