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 tipoIterator
retornado 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 word in &v { println!("palavra: {word}"); } for word in v { println!("palavra: {word}"); } }
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.