أسئلة متقدمة في مقابلات Rust: تحليل وأمثلة

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

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

ابدأ الدورة

كيف تجتاز مقابلة Rust: أهم الأسئلة المتقدمة



Rust هي واحدة من أكثر لغات البرمجة النظامية طلبًا، ولا يزال الطلب على مطوري senior في ازدياد. إذا كنت قد أتقنت بالفعل بناء الجملة الأساسي ونظام الملكية، فستواجه في المقابلة أسئلة تختبر فهمك العميق لـ unsafe-code، وعدم التزامن، وأوقات الحياة المعقدة، والبرمجة الوصفية. في هذه المقالة، سنناقش المواضيع الرئيسية ونقدم أمثلة كود ستساعدك على اجتياز المقابلة بثقة.



1. Unsafe Rust: متى ولماذا؟



أحد أكثر الأسئلة شيوعًا في المقابلات المتقدمة: "اشرح متى ستستخدم unsafe وما هي الضمانات التي يتم انتهاكها".



يجب أن تتضمن الإجابة أربع إمكانيات رئيسية يوفرها unsafe:



  • إلغاء الإشارة إلى المؤشرات الأولية (*const T و *mut T)
  • استدعاء دوال unsafe (مثل FFI)
  • الوصول إلى المتغيرات الثابتة القابلة للتغيير
  • تنفيذ traits غير الآمنة


مثال: تنفيذ مصفوفة ديناميكية بسيطة مع إدارة يدوية للذاكرة.



use std::alloc::{alloc, dealloc, Layout};use std::ptr;

struct MyVec { ptr: *mut i32, len: usize, cap: usize,}

impl MyVec { fn new() -> Self { MyVec { ptr: ptr::null_mut(), len: 0, cap: 0, } }

fn push(&mut self, val: i32) { if self.len == self.cap { let new_cap = if self.cap == 0 { 1 } else { self.cap * 2 }; let new_layout = Layout::array::<i32>(new_cap).unwrap(); let new_ptr = unsafe { alloc(new_layout) as *mut i32 }; // نسخ البيانات القديمة unsafe { ptr::copy_nonoverlapping(self.ptr, new_ptr, self.len); if !self.ptr.is_null() { let old_layout = Layout::array::<i32>(self.cap).unwrap(); dealloc(self.ptr as *mut u8, old_layout); } } self.ptr = new_ptr; self.cap = new_cap; } unsafe { ptr::write(self.ptr.add(self.len), val); } self.len += 1; }}

impl Drop for MyVec { fn drop(&mut self) { if !self.ptr.is_null() { unsafe { let layout = Layout::array::<i32>(self.cap).unwrap(); dealloc(self.ptr as *mut u8, layout); } } }}


نصيحة: أكد دائمًا أن unsafe ليس تعطيلًا للفحوصات، بل تحمل المسؤولية عن الثوابت.



2. Lifetimes و variance: كيف يتحقق المترجم من المراجع



على المستوى المتقدم، سيُطلب منك شرح ما هو variance (التغاير، التباين، الثبات) في سياق أوقات الحياة. هذا هو المفتاح لفهم سبب عدم ترجمة بعض الأنواع.



  • التغاير: &'a T — إذا كان 'a أكبر من 'b، فيمكن استخدام &'a T كـ &'b T.
  • التباين: fn(T) — إذا كان 'a أكبر من 'b، فيمكن استخدام fn(&'b T) كـ fn(&'a T).
  • الثبات: &mut T — يجب أن يتطابق وقت الحياة تمامًا.


مثال: لماذا لا يتم ترجمة الكود التالي؟



fn foo<'a>(x: &'a mut &'a str, y: &'a str) {    *x = y;}

fn main() { let mut s = "hello"; let r = &s; foo(&mut s, r); // خطأ!}


الإجابة: &mut T ثابت بالنسبة لـ T، لذلك يجب أن يتطابق وقت الحياة للمرجع الداخلي مع وقت الحياة للمرجع الخارجي. لا يمكن للمترجم "ضغط" وقت حياة r.



3. Async Rust: Pin، Unpin و Future

المدونات

توصيات الكتب