iter vs into_iter in Rust: Was steckt unter der Haube?

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

iter vs into_iter: Kampf der Titanen der Iteration in Rust

\n\n

Wenn Sie jemals in Rust eine Schleife über einen Vektor geschrieben haben, sind Sie bestimmt auf die drei Zwillingsbrüder gestoßen: iter(), into_iter() und iter_mut(). Auf den ersten Blick tun sie alle dasselbe – sie ermöglichen es, über die Elemente zu iterieren. Aber der Unterschied zwischen ihnen ist tiefer, als es scheint, und liegt im Herzen von Rust – dem Ownership-System.

\n\n

Stellen Sie sich vor, Sie sind ein Barista und Ihre Sammlung sind Kaffeebohnen. iter() erlaubt Ihnen, die Bohnen anzusehen, an ihnen zu riechen, aber sie nicht zu berühren. into_iter() ist, wenn Sie die Bohnen nehmen, mahlen und einen Espresso machen, wonach die Bohnen verschwinden. Und iter_mut() – Sie können nicht nur schauen, sondern die Bohnen direkt im Beutel mahlen und ihre Form verändern.

\n\n

Heute werden wir iter vs into_iter so aufschlüsseln, wie es auf Stack Overflow erklärt wird, aber mit lebendigen Beispielen und einem tiefen Einblick unter die Haube. Los geht's!

\n\n

Was ist ein Iterator in Rust?

\n\n

Ein Iterator ist ein Objekt, das weiß, wie man sequenziell Elemente aus einer Sammlung erhält. In Rust sind Iteratoren faul: Sie tun nichts, bis Sie next() aufrufen. Aber das Wichtigste ist, dass jede Iterationsmethode das Ownership der Daten unterschiedlich behandelt.

\n\n

Hier sind die drei Hauptansätze:

\n
    \n
  • iter() – leiht sich die Elemente aus (übernimmt kein Ownership)
  • \n
  • into_iter() – konsumiert die Sammlung (übernimmt Ownership)
  • \n
  • iter_mut() – leiht mit der Möglichkeit zur Änderung aus
  • \n
\n\n

Schauen wir uns den Code an. Angenommen, wir haben einen Vektor mit Namen:

\n\n
let names = vec!["Anna".to_string(), "Boris".to_string(), "Viktor".to_string()];
\n\n

Beispiel 1: iter() – nur anschauen

\n\n
fn main() {\n    let names = vec!["Anna".to_string(), "Boris".to_string(), "Viktor".to_string()];\n    \n    // iter() gibt &String zurück (eine Referenz)\n    for name in names.iter() {\n        println!("Hallo, {}!", name);\n    }\n    \n    // names ist immer noch verfügbar!\n    println!("Vektor lebt: {:?}", names);\n}
\n\n

Beachten Sie: Nach der Schleife verwenden wir names problemlos weiter. Warum? Weil iter() eine Referenz auf jedes Element zurückgegeben hat. Das Ownership blieb beim Vektor. Das ist sicher und vorhersehbar.

\n\n

Beispiel 2: into_iter() – die Brücken abbrechen

\n\n
fn main() {\n    let names = vec!["Anna".to_string(), "Boris".to_string(), "Viktor".to_string()];\n    \n    // into_iter() gibt String zurück (Ownership wird verschoben)\n    for name in names.into_iter() {\n        println!("Tschüss, {}!", name);\n    }\n    \n    // Fehler! names existiert nicht mehr\n    // println!("Vektor lebt: {:?}", names); // ❌ borrow of moved value\n}
\n\n

Da haben wir es, der entscheidende Unterschied. into_iter() konsumiert die Sammlung. Jedes Element wird in die Schleife verschoben, und der ursprüngliche Vektor wird ungültig. Wenn Sie die Sammlung für die weitere Verwendung behalten müssen – ist into_iter() nicht Ihre Wahl.

\n\n

Beispiel 3: iter_mut() – ändern, ohne zu zerstören

\n\n
fn main() {\n    let mut names = vec!["Anna".to_string(), "Boris".to_string(), "Viktor".to_string()];\n    \n    // iter_mut() gibt &mut String zurück (eine mutable Referenz)\n    for name in names.iter_mut() {\n        name.push_str(" (Gast)");\n    }\n    \n    println!("Geänderter Vektor: {:?}", names);\n    // Ausgabe: ["Anna (Gast)", "Boris (Gast)", "Viktor (Gast)"]\n}
\n\n

Hier ändern wir die Elemente direkt, ohne das Ownership zu übernehmen. Ideal für Transformationen.

\n\n

Unter der Haube: Was gibt jede Methode zurück?

\n\n

Um iter vs into_iter wirklich zu verstehen, werfen wir einen Blick in die Standardbibliothek. Für den Vektor Vec<T>:

\n\n
    \n
  • iter() gibt std::slice::Iter<T> zurück – implementiert Iterator<Item = &T>

Blogs

Buchempfehlungen