Um die Funktion collect zu verstehen, ist es wichtig zu wissen, dass sie dazu dient, einen Iterator aufzulösen. Zur Erinnerung: Ein Iterator ist eine Folge von Elementen, die sich mit anderen Iteratoren verketten lässt. Iteratoren sind lazy, das heißt, sie werden erst ausgeführt, wenn du Code aufrufst, der den Iterator verbraucht. Zu solchem Code gehören for-Schleifen und verbrauchende Adaptoren. Verbrauchende Adaptoren verarbeiten alle Elemente des Iterators, um eine Art von Ausgabe zu erzeugen.
collect ist ein solcher verbrauchender Adaptor. Du kannst damit eine Instanz jedes Typs erzeugen, der das FromIterator-Trait implementiert. Dieses Trait ist für alle Collections in der Standardbibliothek implementiert. Da FromIterator für viele Typen implementiert ist, musst du Rust mitteilen, welche Art von Collection du haben möchtest. Wenn wir zum Beispiel einen Vec<char> aus einem String-Slice erhalten möchten, können wir den Typ in unseren Aufruf von collect einfügen, und zwar so:
let my_chars = "Hello, World!".chars().collect::<Vec<char>>();
// since the item type of the `String::chars()` iterator can be inferred to be `char`, we can omit that information
// let my_chars = "Hello, World!".chars().collect::<Vec<_>>();
Die doppelten Doppelpunkte und die äußeren spitzen Klammern (also ::<_>) werden als turbofish bezeichnet. In diesem Fall ist der Turbofish mehr syntaktischer Ballast als nötig. Wenn du den Typ direkt an der Bindung angibst, kann collect mit weniger syntaktischem Ballast ableiten, welche Collection es erzeugen soll.
let my_chars: Vec<char> = "Hello, World!".chars().collect();
// or
// let my_chars: Vec<_> = "Hello, World!".chars().collect();
Wenn wir einen String mit umgekehrten Zeichen wollten, könnten wir es so machen:
let rev_chars: String = "Hello, World!".chars().rev().collect();
Rusts Typinferenz ist so mächtig, dass wir manchmal keine ausdrückliche Angabe direkt im Code brauchen:
fn get_reversed_chars(phrase: &str) -> Vec<char> {
phrase.chars().rev().collect()
}
Der Rückgabetyp der Funktion get_reversed_chars lässt die Funktion collect ableiten, welche Collection sie zurückgeben soll. Hier müssen wir allerdings Vec<char> und nicht Vec<_> angeben, da Rust keine Typinferenz für Funktionssignaturen durchführt. Das stellt sicher, dass jemand, der den Code liest, schnell erkennen kann, welche Typen eine Funktion entgegennimmt und zurückgibt.