Я думаю, есть кое-что, чтобы уточнить немного больше. Типы коллекций, такие как 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()эквивалентно тому, &vчто оба реализуют IntoIterator<Item=&T>, почему тогда Rust предоставляет оба? Это для эргономики. В forциклах это немного более сжато, &vчем v.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.