The iterator

Iteration methods such as forEach and map are similar to the array in JS. In Rust, there is also the concept of iterator. The difference is that for_each in RUST, the map method is called an iteration adapter, which is lazy. They don’t have any real effect unless you call them.

Creating iterators

Create an iterator using the iter method and call next to consume it:

let arr = vec![1.2.3];

// Create an iterator
// Because the iterator has a maintenance pointer position inside it, the pointer will be updated with each iteration, so muT needs to be marked
let mut iter = v1.iter();

// Consume iterators
println!("{:? }", iter.next());
println!("{:? }", iter.next());
println!("{:? }", iter.next());
println!("{:? }", iter.next());

// Some(1)
// Some(2)
// Some(3)
// None
Copy the code

In fact and JS very similar, can be recalled:

var arr= [1.2.3];

// Create an iterator
var iter = arr[Symbol.iterator]();

// Consume iterators
iter.next();
iter.next();
iter.next();
iter.next();

// {value: 1, done: false}
// {value: 2, done: false}
// {value: 3, done: false}
// {value: undefined, done: true}
Copy the code

Consumption iterator

Instead of calling the iterator manually using the next method, we can use the for loop to consume the iterator. If the result of the iteration is Some, the for loop will continue iterating until None is encountered:

let arr = vec![1.2.3];
let iter = arr.iter();

// Because the for loop consumes iterators, it takes ownership of iter
for item in iter {
  println!("{}", item)
  / / 1
  / / 2
  / / 3
}

println!("{:? }", iter) // Error reported, ownership has been moved
Copy the code

The iterator traits

Not all types can iterate. Types that can iterate need to implement the Iterator trait:

pub trait Iterator {
  // This will be described later: association types
  type Item;
  // Each iterator has a next method,
  // It returns an iterator element wrapped in Some each time it is called,
  // And returns None at the end of the iteration.
  fn next(&mut self) - >Option<Self::Item>;
}
Copy the code

Implement iterator traits for custom constructs:

// Define a counter structure
struct Counter {
  // Iterate over the maximum value
  max: u32./ / the current value
  current: u32
}

// Implement the iterator trait
impl Iterator for Counter {
  // Specify the type of each iteration
  type Item = u32;

  // Implement the next method
  fn next(&mut self) - >Option<Self::Item>{
    // If the current value is greater than or equal to the maximum value, at the end of the iteration, None is returned
    if self.current >= self.max {
      None
    } else {
      // Get the current value
      let val = self.current;
      // Add 1 for the next iteration
      self.current += 1;
      // Return current value
      Some(val)
    }
  }
}

let counter = Counter {
  current: 0,
  max: 3
};

// You can use the for loop directly
for item in counter {
  println!("{}", item);
  / / 1
  / / 2
  / / 3
}
Copy the code

Iterator type

When consuming iter iterators, we get an immutable reference to each member. There are actually three types of iterators available:

  • Iter: Gets an immutable reference to a member
  • Iter_mut: Gets a mutable reference to a member
  • Into_iter: Takes ownership of a member

Consumer adapter

Rust has a number of built-in methods for consuming iterators that take ownership of the iterator and repeatedly call next to iterate over elements, such as the sum method over the members of an array:

let arr = [1.2.3];
let iter = v3.iter();

// the sum method takes ownership of the iterator.
// The iterator can no longer be used
let total: i32 = iter.sum();
println!("{}", total); / / 6
Copy the code

Iterator adapter

Rust also has a number of built-in methods for chain-manipulating members through iterators. These methods are lazy and iterative adapter methods are executed only after the last call to a method that consumes the adapter, such as the Map iterator adapter:

let arr = [1.2.3];
// map creates a new iterator and returns,
// Since the iterator adapter is lazy, nothing happens unless the iterator is consumed,
// The compile will alert you because no consumption has been made
arr.iter().map(|x| x + 1);
Copy the code

Using the Collect consumer adapter:

// collect consumes the iterator and collects the resulting value into some collection data type
let arr = [1.2.3];

// Note that to use collect you need to specify the final type
let arr2: Vec<i32> = arr.iter().map(|x| x + 1).collect();
/ / equivalent to the
let arr2 = arr.iter().map(|x| x + 1).collect::<Vec<i32> > ();println!("{:? }", arr2); / / [2, 3, 4]
Copy the code

The filter iterative adapter is used to filter members:

#[derive(Debug)]
struct Shoe {
  size: u32
}
let arr = vec![
  Shoe { size: 40 },
  Shoe { size: 41 },
  Shoe { size: 42},];// filter will filter Shoe whose size is greater than 40
let arr2: Vec<_> = arr.iter().filter(|x| x.size > 40).collect();

println!("{:? }", arr2);
// [Shoe { size: 41 }, Shoe { size: 42 }]
Copy the code

A more complex example of an iterative adapter:

// Use the above custom structure Counter
let sum: u32 = Counter {
  current: 0,
  max: 5
}
// zip: combine into: (1,2) (2,3) (3,4) (4,5), since the last (5, None) since one of them is None, will not be generated
.zip(Counter {
  current: 0,
  max: 5
  // skip: zip with 1,2,3,4
}.skip(1))
// Map after mapping: 2, 6, 12, 20
.map(|(a, b)| a * b)
// filter: 6 12
.filter(|x| x % 3= =0)
// sum求和:6 + 12
.sum();

println!("{}", sum); / / 18
Copy the code