Iteradores e Ownership (Posse)
O modelo de ownership do Rust afeta muitas APIs. Um exemplo disso são os traits Iterator e IntoIterator.
Iterator (Iterador)
Os traits são como interfaces: eles descrevem o comportamento (métodos) para um tipo. O trait Iterator simplesmente diz que você pode chamar next até obter None como retorno:
#![allow(unused)] fn main() { pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; } }
Você usa esse trait da seguinte forma:
fn main() { let v: Vec<i8> = vec![10, 20, 30]; let mut iter = v.iter(); println!("v[0]: {:?}", iter.next()); println!("v[1]: {:?}", iter.next()); println!("v[2]: {:?}", iter.next()); println!("Sem mais itens: {:?}", iter.next()); }
Qual é o tipo retornado pelo iterador? Teste sua resposta aqui:
fn main() { let v: Vec<i8> = vec![10, 20, 30]; let mut iter = v.iter(); let v0: Option<..> = iter.next(); println!("v0: {v0:?}"); }
Por que esse tipo?
IntoIterator
O trait Iterator informa como iterar depois de criar um iterador. O trait relacionado IntoIterator lhe informa como criar o iterador:
#![allow(unused)] fn main() { pub trait IntoIterator { type Item; type IntoIter: Iterator<Item = Self::Item>; fn into_iter(self) -> Self::IntoIter; } }
A sintaxe aqui significa que toda implementação de IntoIterator deve declarar dois tipos:
Item: o tipo sobre o qual iteramos, comoi8,IntoIter: o tipoIteratorretornado pelo métodointo_iter.
Observe que IntoIter e Item estão vinculados: o iterador deve ter o mesmo tipo Item, o que significa que ele retorna Option<Item>
Como antes, qual é o tipo retornado pelo iterador?
fn main() { let v: Vec<String> = vec![String::from("foo"), String::from("bar")]; let mut iter = v.into_iter(); let v0: Option<..> = iter.next(); println!("v0: {v0:?}"); }
Loops for
Agora que conhecemos Iterator e IntoIterator, podemos construir loops for. Eles chamam into_iter() em uma expressão e itera sobre o iterador resultante:
fn main() { let v: Vec<String> = vec![String::from("foo"), String::from("bar")]; for palavra in &v { println!("palavra: {palavra}"); } for palavra in v { println!("palavra: {palavra}"); } }
Qual é o tipo de palavra em cada laço?
Experimente com o código acima e depois consulte a documentação para impl IntoIterator para &Vec<T> e impl IntoIterator para Vec<T> para verificar suas respostas.