Saya pikir ada sesuatu yang perlu diklarifikasi sedikit lagi. Jenis koleksi, seperti Vec<T>
dan VecDeque<T>
, memiliki into_iter
metode yang menghasilkan T
karena mereka menerapkan IntoIterator<Item=T>
. Tidak ada yang menghentikan kita untuk membuat tipe Foo<T>
jika yang diulangi, itu akan menghasilkan bukan T
tipe lain U
. Yaitu, Foo<T>
implementasinya IntoIterator<Item=U>
.
Bahkan, ada beberapa contoh di std
: &Path
alat IntoIterator<Item=&OsStr>
dan &UnixListener
alat IntoIterator<Item=Result<UnixStream>>
.
Perbedaan antara into_iter
daniter
Kembali ke pertanyaan awal tentang perbedaan antara into_iter
dan iter
. Serupa dengan yang ditunjukkan orang lain, perbedaannya adalah into_iter
metode yang diperlukan IntoIterator
yang dapat menghasilkan jenis apa pun yang ditentukan IntoIterator::Item
. Biasanya, jika suatu tipe mengimplementasikan IntoIterator<Item=I>
, dengan konvensi ia juga memiliki dua metode ad-hoc: iter
dan iter_mut
yang menghasilkan &I
dan &mut I
, masing-masing.
Apa yang tersirat adalah bahwa kita dapat membuat fungsi yang menerima tipe yang memiliki into_iter
metode (yaitu iterable) dengan menggunakan sifat terikat:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
Namun, kita tidak dapat * menggunakan suatu sifat yang terikat untuk meminta suatu tipe untuk memiliki iter
metode atau iter_mut
metode, karena itu hanya konvensi. Kita dapat mengatakan bahwa into_iter
itu lebih banyak digunakan daripada iter
atau iter_mut
.
Alternatif untuk iter
daniter_mut
Yang menarik untuk diamati adalah bahwa iter
itu bukan satu-satunya cara untuk mendapatkan iterator yang menghasilkan &T
. Dengan konvensi (lagi), jenis koleksi SomeCollection<T>
di std
mana memiliki iter
metode juga memiliki referensi jenis berubah mereka &SomeCollection<T>
melaksanakan IntoIterator<Item=&T>
. Misalnya, &Vec<T>
mengimplementasikan IntoIterator<Item=&T>
, sehingga memungkinkan kita untuk beralih &Vec<T>
:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Jika v.iter()
setara dengan &v
kedua implementasi tersebut IntoIterator<Item=&T>
, mengapa Rust menyediakan keduanya? Ini untuk ergonomi. Dalam for
loop, ini sedikit lebih ringkas untuk digunakan &v
daripada v.iter()
; tetapi dalam kasus lain, v.iter()
jauh lebih jelas daripada (&v).into_iter()
:
let v = vec![1, 2];
let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();
Demikian pula, dalam for
loop, v.iter_mut()
dapat diganti dengan &mut v
:
let mut v = vec![1, 2];
// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
*item *= 2;
}
Kapan harus menyediakan (mengimplementasikan) into_iter
dan iter
metode untuk suatu jenis
Jika tipe hanya memiliki satu "cara" untuk diulangi, kita harus mengimplementasikan keduanya. Namun, jika ada dua cara atau lebih yang dapat diulangi, kita harus menyediakan metode ad-hoc untuk setiap cara.
Misalnya, String
tidak menyediakan into_iter
atau iter
karena ada dua cara untuk mengulanginya: untuk mengulangi perwakilannya dalam byte atau untuk mengulangi perwakilannya dalam karakter. Alih-alih, ia menyediakan dua metode: bytes
untuk iterasi byte dan chars
untuk iterasi karakter, sebagai alternatif iter
metode.
* Yah, secara teknis kita bisa melakukannya dengan menciptakan suatu sifat. Tetapi kemudian kita perlu impl
sifat itu untuk setiap jenis yang ingin kita gunakan. Sementara itu, banyak tipe yang std
sudah diimplementasikan IntoIterator
.