Я думаю, що є щось, щоб уточнити трохи більше. Типи колекцій, такі як Vec<T>і VecDeque<T>, мають into_iterметод, який дає результати, Tоскільки вони реалізовані IntoIterator<Item=T>. Ніщо не зупинить нас, щоб створити тип, Foo<T>якщо це повторено, це призведе не до Tіншого типу U. Тобто Foo<T>знаряддя IntoIterator<Item=U>.
Насправді, є кілька прикладів у std: &Path реалізаціях IntoIterator<Item=&OsStr> та &UnixListener реалізаціях IntoIterator<Item=Result<UnixStream>> .
Різниця між into_iterіiter
Повернутися до початкового питання про різницю між into_iterта iter. Аналогічно тому, що вказували інші, різниця полягає в тому into_iter, що необхідний метод IntoIteratorдозволяє отримати будь-який тип, зазначений у IntoIterator::Item. Як правило, якщо тип реалізується IntoIterator<Item=I>, за умовою він також має два спеціальні методи: iterі iter_mutякі приносять &Iі &mut I, відповідно.
Це означає, що ми можемо створити функцію, яка отримує тип, який має into_iterметод (тобто він є ітерабельним), використовуючи прив’язану ознаку:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
Однак ми не можемо * використовувати ознаку, прив’язану до того, щоб вимагати типу, щоб мати iterметод чи iter_mutметод, оскільки вони є лише умовами. Ми можемо сказати, що into_iterбільш широко застосовується, ніж iterабо iter_mut.
Альтернативи iterтаiter_mut
Ще одне цікаве зауваження - iterце не єдиний спосіб отримати ітератор, який дає результат &T. За умовою (знову ж таки) типи колекцій, SomeCollection<T>у stdяких є iterметод, також &SomeCollection<T>реалізують свої незмінні типи посилань IntoIterator<Item=&T>. Наприклад, &Vec<T> інструменти IntoIterator<Item=&T> , так що це дозволяє нам повторити &Vec<T>:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Якщо в обох реалізаціях v.iter()рівнозначно , чому тоді Rust надає обоє? Це для ергономіки. У циклах використовувати трохи більш стисло, ніж ; але в інших випадках набагато зрозуміліше, ніж :&vIntoIterator<Item=&T>for&vv.iter()v.iter()(&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();
Аналогічно, у forциклах, v.iter_mut()можна замінити на &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;
}
Коли надати (реалізувати) into_iterта iterметоди для типу
Якщо тип має лише один "спосіб" перегляду, ми повинні реалізувати обидва. Однак, якщо є два способи або більше, це можна повторити, замість цього ми повинні запропонувати спеціальний метод для кожного способу.
Наприклад, Stringне передбачено into_iterні iterтому, що є два способи його ітерації: повторити його представлення в байтах або повторити його представлення в символах. Натомість він пропонує два методи: bytesдля ітерації байтів та charsдля ітерації символів як альтернативи iterметоду.
* Ну, технічно ми можемо це зробити, створивши ознаку. Але тоді нам потрібна implця риса для кожного типу, який ми хочемо використовувати. Тим часом, багато типів stdуже реалізовані IntoIterator.