Di bawah ini adalah terjemahan dari salah satu bagian dari serial artikel Rust Crash Course oleh Michael Snoiman, yang berfokus pada iterator. Materi tersebut bagi saya tampaknya berhasil dalam hal aksesibilitas, jadi saya memutuskan untuk menerbitkan terjemahan yang saya buat sendiri. Semoga ini bermanfaat bagi seseorang. Jika materi ini menarik, maka saya akan menerbitkan beberapa terjemahan lagi dari seri ini.
Saya juga mencoba menerjemahkan sedekat mungkin dengan gaya pengarang, tetapi mengurangi beberapa sela dan seruan yang tidak terlalu signifikan artinya.
Lebih banyak iterator!
Bagi saya sendiri, saya telah menemukan bahwa cara termudah untuk memahami cara kerja iterator adalah dengan menulis beberapa di antaranya sendiri, jadi di situlah kami memulai.
Mari kita lakukan pemrograman yang dipandu kompiler. Kami telah membahas sebelumnya bahwa ada ciri Iterator
. Jadi saya yakin kita perlu membuat tipe data baru dan memberikan implementasi untuk sifat ini. Mari kita mulai dengan sesuatu yang sederhana, iterator yang tidak menghasilkan nilai sama sekali.
struct Empty;
fn main() {
for i in Empty {
panic!("Wait, this shouldn't happen!");
}
println!("All done!");
}
Panic ( panic!()
) adalah cara untuk menghentikan utas saat ini ketika situasi yang tidak mungkin terjadi. Ini mirip dengan pengecualian waktu proses dalam bahasa lain, kecuali bahwa itu tidak dapat dipulihkan. Jadi seharusnya hanya digunakan untuk situasi seperti itu.
Mari kita kompilasi ini dan dapatkan pesan kesalahan yang berguna:
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`
Mari tambahkan implementasi kosong:
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);
}
}
, .
Mari kita mulai dengan solusi paling sederhana
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);
}
}
Namun jika diganti take(10)
dengan take(47)
, maka output program akan terlihat seperti ini:
701408733 1134903170 thread 'main' panicked at 'attempt to add with overflow', foo.rs:21:18 note: Run with `RUST_BACKTRACE=1` for a backtrace.
Salah satu solusinya mungkin menggunakan tipe u64
, tapi itu hanya akan menunda masalah. Kita bisa menggunakan penambahan overflow sebagai gantinya:
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)
}