Fortgeschrittene Rust-Interviewfragen: Analyse und Beispiele

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Wie man ein Rust-Interview besteht: Top-Fragen für Fortgeschrittene



Rust ist eine der gefragtesten Systemprogrammiersprachen, und die Nachfrage nach Senior-Entwicklern wächst weiter. Wenn Sie bereits die grundlegende Syntax und das Ownership-System beherrschen, erwarten Sie im Interview Fragen, die ein tiefes Verständnis von unsafe-Code, Asynchronität, komplexen Lifetimes und Metaprogrammierung prüfen. In diesem Artikel analysieren wir die wichtigsten Themen und geben Codebeispiele, die Ihnen helfen, das Interview souverän zu bestehen.



1. Unsafe Rust: Wann und warum?



Eine der häufigsten Fragen in fortgeschrittenen Interviews: „Erklären Sie, wann Sie unsafe verwenden würden und welche Garantien dabei verletzt werden.“



Die Antwort sollte die vier Hauptmöglichkeiten umfassen, die unsafe bietet:



  • Dereferenzieren von rohen Zeigern (*const T und *mut T)
  • Aufrufen von unsafe-Funktionen (z. B. FFI)
  • Zugriff auf veränderliche statische Variablen
  • Implementieren von unsafe-Traits


Beispiel: Implementierung eines einfachen dynamischen Arrays mit manueller Speicherverwaltung.



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 }; // alte Daten kopieren 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); } } }}


Tipp: Betonen Sie immer, dass unsafe keine Deaktivierung von Prüfungen ist, sondern die Übernahme der Verantwortung für Invarianten.



2. Lifetimes und Varianz: Wie der Compiler Referenzen prüft



Auf fortgeschrittenem Niveau werden Sie gebeten, Varianz (Kovarianz, Kontravarianz, Invarianz) im Kontext von Lifetimes zu erklären. Dies ist der Schlüssel zum Verständnis, warum manche Typen nicht kompilieren.



  • Kovarianz: &'a T – wenn 'a größer als 'b ist, kann &'a T als &'b T verwendet werden.
  • Kontravarianz: fn(T) – wenn 'a größer als 'b ist, kann fn(&'b T) als fn(&'a T) verwendet werden.
  • Invarianz: &mut T – die Lifetime muss exakt übereinstimmen.


Beispiel: Warum kompiliert der folgende Code nicht?



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); // Fehler!}


Antwort: &mut T ist invariant bezüglich T, daher muss die Lifetime des inneren Verweises mit der Lifetime des äußeren übereinstimmen. Der Compiler kann die Lifetime von r nicht „verkürzen“.



3. Async Rust: Pin, Unpin und Future

Blogs

Buchempfehlungen