Eu acho que há algo para esclarecer um pouco mais. Tipos de coleção, como Vec<T>e VecDeque<T>, têm um into_itermétodo que gera Tporque eles implementam IntoIterator<Item=T>. Não há nada para nos impedir de criar um tipo, Foo<T>se for iterado, ele produzirá não Tapenas outro tipo U. Ou seja, Foo<T>implementa IntoIterator<Item=U>.
De fato, existem alguns exemplos em std: &Path implementos IntoIterator<Item=&OsStr> e &UnixListener implementos IntoIterator<Item=Result<UnixStream>> .
A diferença entre into_itereiter
Voltar à pergunta original sobre a diferença entre into_itere iter. Semelhante ao que outros já apontaram, a diferença é que into_iteré um método exigido IntoIteratorque pode gerar qualquer tipo especificado em IntoIterator::Item. Normalmente, se um tipo é implementado IntoIterator<Item=I>, por convenção, ele também possui dois métodos ad-hoc: itere iter_mutque produzem &Ie &mut I, respectivamente.
O que isso implica é que podemos criar uma função que recebe um tipo que possui into_itermétodo (ou seja, é iterável) usando um atributo vinculado:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
No entanto, não podemos * usar uma característica vinculada para exigir que um tipo tenha itermétodo ou iter_mutmétodo, porque são apenas convenções. Podemos dizer que into_iteré mais amplamente utilizável que iterou iter_mut.
Alternativas itereiter_mut
Outro interessante a observar é que iternão é a única maneira de obter um iterador que produza &T. Por convenção (novamente), os tipos de coleção SomeCollection<T>nos stdquais o itermétodo também tem seus tipos de referência imutáveis &SomeCollection<T>implementados IntoIterator<Item=&T>. Por exemplo, &Vec<T> implementa IntoIterator<Item=&T> , portanto, permite iterar sobre &Vec<T>:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Se v.iter()é equivalente a &vque ambos implementam IntoIterator<Item=&T>, por que então Rust fornece ambos? É para ergonomia. Em forloops, é um pouco mais conciso do &vque v.iter(); mas em outros casos, v.iter()é muito mais claro que (&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();
Da mesma forma, em forloops, v.iter_mut()pode ser substituído por &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;
}
Quando fornecer (implementar) into_itere itermétodos para um tipo
Se o tipo tiver apenas uma "maneira" de ser repetida, devemos implementar as duas. No entanto, se há duas maneiras ou mais para iterar, devemos fornecer um método ad-hoc para cada maneira.
Por exemplo, Stringfornece nem into_iternem iterporque existem duas maneiras de iterá-lo: iterar sua representação em bytes ou iterar sua representação em caracteres. Em vez disso, fornece dois métodos: bytespara iterar os bytes e charspara iterar os caracteres, como alternativas ao itermétodo.
* Bem, tecnicamente, podemos fazer isso criando uma característica. Mas então precisamos impldessa característica para cada tipo que queremos usar. Enquanto isso, muitos tipos stdjá implementam IntoIterator.