Iteration über Vec mit Index in Rust: Vom Anfänger zum Profi
Stellen Sie sich vor: Sie programmieren in Rust und müssen über die Elemente eines Vektors iterieren, dabei aber nicht nur den Wert, sondern auch seine Position kennen. Eine scheinbar einfache Aufgabe, die bei Anfängern jedoch oft für Verwirrung sorgt. Wo ist das for i in range(len(vec)) wie in Python? Was, wenn ich Elemente ändern möchte? Und was ist schneller?
In diesem Artikel analysieren wir alle gängigen Methoden zur Iteration über Vec mit Index in Rust, vergleichen ihre Leistung, Lesbarkeit und Sicherheit. Sie erfahren, welche Methode Sie im Jahr 2024 wählen sollten und warum enumerate nicht immer die silberne Kugel ist.
Warum ist das wichtig?
In Rust gibt es nicht den einen klassischen Weg for i in 0..vec.len(). Die Sprache bietet mehrere Paradigmen: von funktionalen Iteratoren bis hin zu Low-Level-Schleifen. Den Unterschied zu verstehen, ist der Schlüssel zum Schreiben von effizientem und idiomatischem Code. Dies ist besonders kritisch bei der Arbeit mit Vektoren, wo der Index für die Änderung benachbarter Elemente oder die Verfolgung der Position in einem Algorithmus benötigt wird.
Methode 1: Der Klassiker — enumerate
Die gebräuchlichste und empfohlene Methode. Die Methode enumerate umschließt den Iterator und fügt jedem Element seinen Index hinzu:
let vec = vec!["a", "b", "c", "d"];for (index, value) in vec.iter().enumerate() { println!("Position {}: {}", index, value);}Vorteile:
- Idiomatisch und lesbar
- Sicher — kein Risiko eines Indexfehlers
- Funktioniert mit jedem Iterator, nicht nur mit Vec
Nachteile: Elemente des Vektors können nicht direkt geändert werden (dafür wird iter_mut() benötigt).
Methode 2: Über Indizes — 0..vec.len()
Ein Ansatz, der allen aus C++ oder Python bekannt ist. Wir verwenden einen Indexbereich:
let mut vec = vec![10, 20, 30, 40];for i in 0..vec.len() { vec[i] += i; // Element über Index ändern println!("vec[{}] = {}", i, vec[i]);}Vorteile:
- Volle Kontrolle über Index und Element
- Elemente können über
vec[i]geändert werden - Für Anfänger intuitiv verständlich
Nachteile: Langsamer als Iteratoren (zusätzliche Grenzprüfung). Die Rust-Community betrachtet ihn als "nicht idiomatisch".
Methode 3: while mit Zähler
Die "manuellste" Methode, die man in altem Code oder bei Optimierungen findet:
let vec = vec![1.0, 2.0, 3.0];let mut i = 0;while i < vec.len() { println!("Element {}: {}", i, vec[i]); i += 1;}Vorteile: Maximale Flexibilität (man kann im Index springen, die Schrittweite ändern).
Nachteile: Leicht, einen Fehler in der Bedingung zu machen. Ohne triftigen Grund nicht empfohlen.
Methode 4: zip mit Bereich
Ein funktionaler Ansatz, wenn zwei Vektoren parallel mit Indizes durchlaufen werden sollen:
let names = vec!["Alice", "Bob", "Charlie"];let scores = vec![95, 87, 92];
for (i, (name, score)) in (0..).zip(names.iter()).zip(scores.iter()) { println!("{}: {} hat {} Punkte erzielt", i, name, score);}Vorteile: Leistungsstark für parallele Iteration. Der unendliche Bereich 0.. wird automatisch abgeschnitten.
Nachteile: Kann schwer zu lesen sein. Für einfache Aufgaben überdimensioniert.
Leistungsvergleich
Wir haben Benchmarks mit einem Vektor von 100.000 Elementen durchgeführt (Optimierung --release):
| Methode | Zeit (ns) | Rel. Geschwindigkeit |
|---|---|---|
enumerate | ~12 000 | 1.0x (Referenz) |
0..len | ~15 000 | 1.25x langsamer |