Abaixo está uma tradução de uma parte da série de artigos Rust Crash Course de Michael Snoiman, que se concentra em iteradores. O material me pareceu um sucesso em termos de acessibilidade, então decidi publicar a tradução que fiz para mim. Espero que isso seja útil para alguém. Se este material for interessante, publicarei mais algumas traduções desta série.
Também tentei traduzir o mais próximo possível do estilo do autor, mas reduzi alguns interdomínios e exclamações que não são muito significativos para o significado.
Mais iteradores!
Para mim, descobri que a maneira mais fácil de entender como funcionam os iteradores é escrever alguns deles eu mesmo, então é por aí que começamos.
Vamos fazer programação guiada por compilador. Discutimos anteriormente que existe uma característica Iterator
. Portanto, aposto que precisamos criar um novo tipo de dados e fornecer uma implementação para esse traço. Vamos começar com algo simples, um iterador que não produz nenhum valor.
struct Empty;
fn main() {
for i in Empty {
panic!("Wait, this shouldn't happen!");
}
println!("All done!");
}
Panic ( panic!()
) é uma forma de encerrar a thread atual quando ocorre uma situação impossível. Isso é semelhante às exceções de tempo de execução em outras linguagens, exceto que não pode ser recuperado. Portanto, ele só deve ser usado para tais situações.
Vamos compilar isso e obter uma mensagem de erro útil:
error[E0277]: `Empty` is not an iterator --> src/main.rs:5:14 | 5 | for i in Empty { | ^^^^^ `Empty` is not an iterator | = help: the trait `std::iter::Iterator` is not implemented for `Empty` = note: required by `std::iter::IntoIterator::into_iter`
Vamos adicionar uma implementação vazia:
impl Iterator for Empty {
}
:
error[E0046]: not all trait items implemented, missing: `Item`, `next` --> src/main.rs:4:1 | 4 | impl Iterator for Empty { | ^^^^^^^^^^^^^^^^^^^^^^^ missing `Item`, `next` in implementation | = help: implement the missing item: `type Item = Type;` = help: implement the missing item: `fn next(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item> { todo!() }`
, : Item
next()
, , . type Item
? , (associated type). , . , . u32
:
struct Empty;
impl Iterator for Empty {
type Item = u32;
}
- next
. :
fn(&mut Self) -> std::option::Option<<Self as std::iter::Iterator>::Item>
. — &mut Self
. , &mut self
. ? , &mut self
— self: &mut Self
.
fn(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item>
Option
Iterator
, (namespace):
fn(&mut self) -> Option<<Self as Iterator>::Item>
Self as Iterator
: " Iterator
". , , — ::Item
. , , " Item
, Iterator
". , , .
, ? :
struct Empty;
impl Iterator for Empty {
type Item = u32;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
unimplemented!()
}
}
unimplemented!()
— , panic!()
. , . () unimplemented!()
.
, as Iterator
, :
fn next(&mut self) -> Option<Self::Item>
, Self::Item
u32
. — , , Item
, . .
. Option
, (enum
) : None
Some
. " ", — " -". , , None
, :
struct Empty;
impl Iterator for Empty {
type item = u32;
fn next(&mut self) -> Option<u32> {
None
}
}
Iterator
.
, 42
. main
.
fn main() {
// only take 10 to avoid looping forever
for i in TheAnswer.take(10) {
println!("The answer to life, the universe, and everything is {}", i);
}
println!("All done!");
}
struct TheAnswer;
impl Iterator for TheAnswer {
type Item = u32;
fn next(&mut self) -> Option<u32> {
Some(42)
}
}
next
self
. ! , 1 10. ( , , , ).
struct OneToTen(u32);
fn one_to_ten() -> OneToTen {
OneToTen(1)
}
impl Iterator for OneToTen {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.0 > 10 {
None
} else {
let res = Some(self.0);
self.0 += 1;
res
}
}
}
fn main() {
for i in one_to_ten() {
println!("{}", i);
}
}
, .
Vamos começar com a solução mais simples
struct Fibs {
x: u32,
y: u32,
}
fn fibs() -> Fibs {
Fibs {
x: 0,
y: 1,
}
}
impl Iterator for Fibs {
type Item = u32;
fn next(&mut self) -> Option<u32> {
let orig_x = self.x;
let orig_y = self.y;
self.x = orig_y;
self.y = orig_x + orig_y;
Some(orig_x)
}
}
fn main() {
for i in fibs().take(10) {
println!("{}", i);
}
}
No entanto, se você substituir take(10)
por take(47)
, a saída do programa ficará assim:
701408733 1134903170 thread 'main' panicked at 'attempt to add with overflow', foo.rs:21:18 note: Run with `RUST_BACKTRACE=1` for a backtrace.
Uma solução pode ser usar um tipo u64
, mas isso apenas adia o problema. Em vez disso, podemos usar a adição de estouro:
fn next(&mut self) -> Option<u32> {
let orig_x = self.x;
let orig_y = self.y;
match orig_x.checked_add(orig_y) {
// overflow
None => None,
// no overflow
Some(new_y) => {
self.x = orig_y;
self.y = new_y;
Some(orig_x)
}
}
}
, .
, . , enum
:
fn next(&mut self) -> Option<u32> {
use Fibs::*;
match *self {
Done => None,
OneLeft(x) => {
*self = Done;
Some(x)
}
Running(orig_x, orig_y) => {
*self = match orig_x.checked_add(orig_y) {
// overflow
None => OneLeft(orig_y),
Some(new_y) => Running(orig_y, new_y),
};
Some(orig_x)
}
}
}
:
enum FibonacciIterState {
FirstItem,
SecondItem,
NthItem(u64, u64),
Overflowed,
}
struct FibonacciIterator {
state: FibonacciIterState,
}
impl FibonacciIterator {
fn new() -> FibonacciIterator {
FibonacciIterator{ state: FibonacciIterState::FirstItem }
}
}
impl Iterator for FibonacciIterator {
type Item = u64;
fn next(&mut self) -> Option<<FibonacciIterator as Iterator>::Item> {
match self.state {
FibonacciIterState::FirstItem => {
self.state = FibonacciIterState::SecondItem;
Some(0)
},
FibonacciIterState::SecondItem => {
self.state = FibonacciIterState::NthItem(0, 1);
Some(1)
},
FibonacciIterState::NthItem(prev, last) => {
if let Some(next) = prev.checked_add(last) {
self.state = FibonacciIterState::NthItem(last, next);
Some(next)
} else {
self.state = FibonacciIterState::Overflowed;
None
}
},
FibonacciIterState::Overflowed => {
None
}
}
}
}
, . (Doubler), , . , , , :
struct Doubler<I> {
iter: I,
}
main
, , :
fn main() {
let orig_iter = 1..11; // 1 10
let doubled_iter = Doubler {
iter: orig_iter,
};
for i in doubled_iter {
println!("{}", i);
}
}
, - Iterator
. :
impl Iterator for Doubler {
}
:
error[E0107]: wrong number of type arguments: expected 1, found 0 --> src/main.rs:6:19 | 6 | impl Iterator for Doubler { | ^^^^^^^ expected 1 type argument
, . Doubler
, . :
impl Iterator for Doubler<I> {
}
. , . (: , ).
:
error[E0412]: cannot find type `I` in this scope --> foo.rs:5:27 | 5 | impl Iterator for Doubler<I> { | ^ not found in this scope
? , , . :
impl<I> Iterator for Doubler<I> {
}
( ), , .
, type Item
next
. u32
:
type Item = u32;
fn next(&mut self) -> Option<u32> {
unimplemented!()
}
, unimplemented!
. , !
, . ( : , map
Option
, ):
fn next(&mut self) -> Option<u32> {
match self.iter.next() {
None => None,
Some(x) => Some(x * 2),
}
}
, :
error[E0599]: no method named `next` found for type parameter `I` in the current scope --> src/main.rs:9:25 | 9 | match self.iter.next() { | ^^^^ method not found in `I` | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following traits define an item `next`, perhaps you need to restrict type parameter `I` with one of them: | 6 | impl<I: std::iter::Iterator> Iterator for Doubler<I> { | ^^^^^^^^^^^^^^^^^^^^^^ 6 | impl<I: std::str::pattern::Searcher> Iterator for Doubler<I> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
, next
Iterator
. . , . , ! , I
Iterator
.
impl<I: Iterator> Iterator for Doubler<I>
, : I
Iterator
. , , :
error[E0369]: cannot multiply `{integer}` to `<I as std::iter::Iterator>::Item` --> src/main.rs:11:31 | 11 | Some(x) => Some(x * 2), | - ^ - {integer} | | | <I as std::iter::Iterator>::Item | = note: the trait `std::ops::Mul` is not implemented for `<I as std::iter::Iterator>::Item`
. I
— - Iterator
, . , x
, x * 2
I
Item
. , , , !
, u32
, , Item
u32
? !
impl<I: Iterator<Item=u32>> Iterator for Doubler<I>
, !
: where
, impl
. where
:
impl<I> Iterator for Doubler<I>
where I: Iterator<Item=u32>
. (consistency) , where
. . .
u32
, u32
. , main
:
let orig_iter = 1..11u64;
:
error[E0271]: type mismatch resolving `<std::ops::Range<u64> as std::iter::Iterator>::Item == u32` --> src/main.rs:24:14 | 24 | for i in doubled_iter { | ^^^^^^^^^^^^ expected `u64`, found `u32` | = note: required because of the requirements on the impl of `std::iter::Iterator` for `Doubler<std::ops::Range<u64>>`
, . ! u32
. :
impl<I> Iterator for Doubler<I>
where I: iterator
{
type Item = ???;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(x) => Some(x * 2),
}
}
}
Option<u32>
Option<Self::Item>
<Item = u32>
I: Iterator
. type Item=
? , , Item
. !
type Item = I::Item;
! , , I::Item
. , Mul
, . :
where
I: Iterator,
I::Item: std::ops::Mul,
:
error[E0308]: mismatched types --> foo.rs:14:29 | 14 | Some(x) => Some(x * From::from(2u8)), | ^^^^^^^^^^^^^^^^^^^ expected std::iter::Iterator::Item, found std::ops::Mul::Output | = note: expected type `<I as std::iter::Iterator>::Item` found type `<<I as std::iter::Iterator>::Item as std::ops::Mul>::Output`
, Mul
. . , (Force
), (Mass
) (Acceleration
), Mul
, (Mass
) (Acceleration
), (Force
).
, . , , item
:
impl<I> Iterator for Doubler<I>
whereI: Iterator,
I::Item: std::ops::Mul<Output=I::Item>,
:
error[E0308]: mismatched types --> foo.rs:14:33 | 14 | Some(x) => Some(x * 2), | ^ expected associated type, found integral variable | = note: expected type `<I as std::iter::Iterator>::Item` found type `{integer}`
. 2
, - . , Item
- . , , ( — , ). , , (upcast) u8
From
, ( ).
impl<I> Iterator for Doubler<I>
where
I: iterator,
I::Item: std::ops::Mul<Output=I::Item> + From<u8>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(x) => Some(x * From::from(2u8)),
}
}
}
, - !
— x + x
x * 2
. . : , , .
impl<I> Iterator for Doubler<I>
where
I: Iterator,
I::Item: std::ops::Add<Output=I::Item> + Copy,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(x) => Some(x + x),
}
}
}
. , , . , . Doubler
, . Empty
, . .
, , . , . , , , .
Doubler
, , . :
fn main() {
for i in (1..11).map(|x| x * 2) {
println!("{}", i);
}
}
Iterator
, . :
fn main() {
for i in (1..11).skip(3).map(|x| x + 1).filter(|x| x % 2 == 0) {
println!("{}", i);
}
}
C/C++, :
- : ,
:
fn main() {
let my_vec: Vec<u32> = (1..11).collect();
println!("{:?}", my_vec);
}
, collect
.
fold
1 10. : sum
.
fold
: . :
fn main() {
let res = (1..11).fold(0, |x, y| x + y);
println!("{}", res);
}
. , Mul
*
? Add
:
fn main() {
let res = (1..11).fold(0, std::ops::Add::add);
println!("{}", res);
}
: , . , From
u8
:
fn sum<I>(iter: I) -> I::Item
where
I: Iterator,
I::Item: std::ops::Add<Output=I::Item> + From<u8>,
{
iter.fold(From::from(0u8), std::ops::Add::add)
}