collect関数を理解するには、これがイテレーターを解決するために使われるものだと知っておくことが大切です。イテレーターとは、他のイテレーターとつなげられる要素の並びのことです。イテレーターは_遅延_です。イテレーターを消費するコードを呼び出すまで、実行されることはありません。そうしたコードにはforループや消費アダプターがあります。消費アダプターは、イテレーターのすべての要素を処理して、何らかの出力を生み出します。
collectもそうした消費アダプターの一つで、FromIteratorトレイトを実装する任意の型のインスタンスを生成するために使えます。このトレイトは、標準ライブラリーにあるすべてのコレクションに実装されています。FromIteratorは多くの型に実装されているので、どんなコレクションが欲しいのかをRustに教えてあげる必要があります。たとえば、文字列スライスからVec<char>を得たいときは、collectの呼び出しに次のように型を書き入れることができます。
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<_>>();
二重コロンと外側の山括弧(つまり::<_>)は、turbofishと呼ばれます。この場合のturbofishは、必要以上に冗長な構文になります。束縛自体で型を指定すると、collectは、より少ない構文でどんなコレクションを作ればよいかを推論できます。
let my_chars: Vec<char> = "Hello, World!".chars().collect();
// or
// let my_chars: Vec<_> = "Hello, World!".chars().collect();
文字を逆順に並べたStringが欲しい場合は、次のように書けます。
let rev_chars: String = "Hello, World!".chars().rev().collect();
Rustの型推論は非常に強力なので、明示的に型を書き添えなくてもよい場合もあります。
fn get_reversed_chars(phrase: &str) -> Vec<char> {
phrase.chars().rev().collect()
}
get_reversed_chars関数の戻り値の型があるおかげで、collect関数はどのコレクションを返せばよいかを推論できます。ただしここでは、Vec<_>ではなくVec<char>を指定しなければなりません。Rustは関数のシグネチャーに対して型推論を行わないからです。これは、コードを読む人が、関数がどんな型を受け取ってどんな型を返すのかをすぐに把握できるようにするためです。