Rust Bites: Iteration

iterators, for-in loops, iterable custom types, iterator methods

Synopsis:

This bit demonstrates Rust iterators walking through enumerable collections. The goal is to build quick familiarity with Rust iteration.
Demo Notes  
All languages covered in this demonstration support iteration through iterators. Enumerable containers provide Rust iterators, exposing the method fn next(&self) -> Option<Self::Item>. This demonstration presents a series of functions that iterate through containers in several forms. It includes demos for library types and a user-defined point class.

1.0 Iterators

Iteration steps through a collection C of values for display or modification. The most basic form uses a loop that calls next() on an iterator.
Iterators use the syntax:
itr.next() -> Option<T>
to step through a collection C. The return value is either Some(val) or None. Here val holds the next item from an instance of C. None indicates that no more items remain.
The instance itr is an iterator returned by c ε C when the code invokes one of three functions:
c.into_iter() Creates an iterator provided by C and consumes c.
Elements of c can be mutated and used during iteration, but c becomes invalid after the call.
c.iter() Returns an iterator without consuming c.
Elements of c cannot be mutated.
c.iter_mut() Returns an iterator without consuming c.
Elements of c can be mutated.

2.0 Source Code

The blocks below start with basic iteration forms and build up to iterators for custom types.

2.1 Loop Iteration over Vec<T>

This block iterates over v, a std::Vec<T>, using a simple loop. The loop displays outputs, and then println!(v) displays them again after the loop. The debug formatter {:?} also uses an iterator to display the vector contents in a slightly different format.
/*---------------------------------------------------------
  Demo Vec iteration with loop construct
  - illustrates how iteration works, using most basic
    syntax operating on Vec<T> instances.
*/
fn demo_loop_iteration() {
  show_label("basic loop iteration with Vec", 35);

  /* 1. v.iter(), iterates without consuming v */
  let v = vec![1, 2, 3, 2, 1];
  show_op("Vec iteration using loop and iter()");
  let mut itr = v.iter();
  loop {
    match itr.next() {
      Some(item) => print!("{item} "),
      None => break,
    }
  }
  // next statement is valid since v not consumed
  println!();
  println!("{v:?}");

  /* 2. v.iter_mut() iterates and mutates without consuming v */
  let mut v = vec![1, 2, 3, 2, 1];
  let mut mitr = v.iter_mut();
  show_op("mutable vec iteration with loop and mut_iter()");
  loop {
    match mitr.next() {
      Some(item) => { *item += 1; print!("{item} "); }
      None => break,
    }
  }
  println!();
  println!("{v:?}");

  /* 3. v.into_iter() consumes v while converting to iterator */
  let mut itr = v.into_iter();
  show_op("generate iterator with v.into_iter()");
  loop {
    match itr.next() {
      Some(item) => print!("{item} "),
      None => break,
    }
  }
  // into_iter() consumes v so the next statement is invalid
  // println!("{v:?}");  // v was moved
  println!();

}




  -----------------------------------
  basic loop iteration with Vec
  -----------------------------------






  --- Vec iteration using loop and iter() ---
  1 2 3 2 1
  [1, 2, 3, 2, 1]












  --- mutable vec iteration with loop and mut_iter() ---
  2 3 4 3 2
  [2, 3, 4, 3, 2]









  --- generate iterator with v.into_iter() ---
  2 3 4 3 2

2.2 Iteration with for-in Loops

For collections c ε C, for-loop iterations usually take one of the forms:
for item in c {
   /* do something with item */
}
for expects an iterator after in. Since collection c is not an iterator, for-in invokes C::into_iterator(). That consumes c.
for item in &c {
   /* do something with item */
}
Since reference &c is not an iterator, for-in invokes &C::into_iterator(). That does not consume c.
for item in &mut c {
   /* do something that mutates item */
}
Since &mut c is not an iterator, for-in invokes &mut C::into_iterator(). That does not consume c.
The first three demonstrations below use iterators directly to show what for-in expects. The last three demonstrations use the three forms from the table above.
/*---------------------------------------------------------
  Demo iteration with for-in loop construct
  - illustrates how for-in works, using idiomatic
    syntax operating on Vec<T> instances.
*/
fn demo_for_iteration() {
  show_label("basic for-in loop iteration using Vec", 45);

  /* 1. v.iter(), iterates without consuming v */
  let v = vec![1, 2, 3, 2, 1];
  show_op("Vec iteration using v.iter()");
  for item in v.iter() {
      print!("{item} ");
  }
  // next statement is valid since v not consumed
  println!();
  println!("{v:?}");

  /* 2. v.iter_mut() iterates and mutates without consuming v */
  let mut v = vec![1, 2, 3, 2, 1];
  show_op("mutable vec iteration using v.iter_mut()");
  println!("original:   {v:?}");
  for item in v.iter_mut() {
    *item += 1;
      print!("{item:?} ");
  }
  println!();
  println!("after iter: {v:?}");

  /* 3. v.into_iter() consumes v while converting to iterator */
  // let mut itr = v.into_iter();
  show_op("for-in uses v.into_iter()");
  for item in v.into_iter() {
    print!("{item:?} ");
  }
  // into_iter() consumes v so the next statement is invalid
  // println!("{v:?}");  // v was moved
  println!();
  /*
     4. iteration with for-in consumes v
        - same as 3. except that into_iter() is used implicitly
        - used in preference to 3
  */
  let v = vec![1, 2, 3, 4, 5];
  show_op("for-in uses v => into_iter()");
  for item in v {  // implicitly uses into_iter()
    print!("{item:?} ");
  }
  // into_iter() consumes v so the next statement is invalid
  // println!("{v:?}");  // v was moved
  println!();

  /*
     5. iteration over elements of v using &v
        - uses internal call to into_iter() implemented with
          Vec::iter() so v not moved
  */
  let v = vec![1, 2, -1, -2, 0];
  show_op("for-in uses &v => iter()");
  for item in &v {
    print!("{item:?} ");
  }
  println!();
  println!("{v:?}");  // v was not moved
  /*
     6. mutating iteration over elements of v using &mut v
        - generates into_iter() implemented with internal
          call to iter_mut(), so does not move v
  */
  let mut v = vec![1, 2, -1, -2, 0];
  show_op("for-in uses &mut v => iter_mut()");
  println!("original: {v:?}");
  for item in &mut v {
    *item += 1;
    print!("{item:?} ");
  }
  println!();
  println!("modified: {v:?}");  // v was not moved

  /*-------------------------------------------------------
    Iteration forms 4, 5, and 6 are the preferred useage.
    Forms 1, 2, and 3 show how for-in loops work.
  -------------------------------------------------------*/
}

                  

                  
                  
---------------------------------------------
  basic for-in loop iteration using Vec
---------------------------------------------







--- Vec iteration using v.iter() ---
1 2 3 2 1
[1, 2, 3, 2, 1]







--- mutable vec iteration using v.iter_mut() ---
original:   [1, 2, 3, 2, 1]
2 3 4 3 2
after iter: [2, 3, 4, 3, 2]







--- for-in uses v.into_iter() ---
2 3 4 3 2











--- for-in uses v => into_iter() ---
1 2 3 4 5












--- for-in uses &v => iter() ---
1 2 -1 -2 0
[1, 2, -1, -2, 0]









--- for-in uses &mut v => iter_mut() ---
original: [1, 2, -1, -2, 0]
2 3 0 -1 1
modified: [2, 3, 0, -1, 1]

2.3 Generate CSL for Several Different Types

Comma separated lists (CSL) present a visually appealing display of collection values. To produce that format, either the first or last item must be formatted differently than the rest to avoid a leading or trailing comma. This code block uses three different strategies to format the list. The last strategy uses the iterator method enumerate() for idiomatic formatting. Section 2.6, below, discusses that method along with several others.
/*---------------------------------------------------------
  Demonstrate iter() by displaying a comma seperated
  list (csl) of items in several common collections.
  - three different strategies used for making
    display comma-seperated
  - syntax used in this demo
    - iter().next() -> Option<Self::Item>
    - enum Option<T> { Some(T), None, }
*/
fn demo_iter() {
  show_label("demo_iter()", 20);

  /*--------------------------------------------------
    iterate over array
    csl strategy #1 extracts first item before iterating
  --------------------------------------------------*/
  show_op("array iter using loop");
  let ar = [1, 2, 3, 4];
  let mut iter = ar.iter();  // extract first item
  if let Some(item) = iter.next() {
    print!("{item}");
  }
  loop {
    let item = iter.next();
    match item {  //display remaining items
      Some(item) => print!(", {}", item),
      None => break
    }
  }
  println!();
  // ar not consumed by ar.iter(), above
  // so statement below is valid:
  println!("using println!:\n{:?}", ar);

  /*--------------------------------------------------
    iterate over Vec
    csl strategy #2 uses first flag
  --------------------------------------------------*/
  /*--- functionaly equivalent to loop, above ---*/
  show_op("Vec iter using for-in");
  let v = vec![1, 2, 3, 4];
  let mut first = true;   // set first flag
  for item in &v {
    if first {
      print!("{item}");
      first = false;            // reset first flag
    }
    else {
      print!(", {item}");
    }
  }
  println!();
  // statement below is valid, v not consumed since
  //   for-in used reference &v
  println!("using println!:\n{:?}", v);

  /*--------------------------------------------------
    iterate over HashMap
    csl strategy #3 uses enumerate()
  --------------------------------------------------*/
  show_op("HashMap iter using for-in");
  let mut hm = HashMap::<&str, i32>::new();
  hm.insert("zero", 0);
  hm.insert("one", 1);
  hm.insert("two", 2);
  hm.insert("three", 3);
  /*-------------------------------------------------------
    enumerate is an iterator adapter that returns another
    iterator yielding (count, value) where value is
    yielded by iter
  */
  for (count, item) in hm.iter().enumerate() {
    if count == 0 {
      print!("{item:?}");
    }
    else {
      print!(", {item:?}");
    }
  }
  println!();
  println!("using println!:\n{:?}", hm);

  /*--------------------------------------------------
    iterate over Point<T, N>,
    csl strategy same as above
  --------------------------------------------------*/
  show_op("Point iter using for-in");
  let mut p = Point::<f64, 5>::new();
  p.init(&vec![1.0, 1.5, 2.0, 1.5, 1.0]);
  for item in p.iter().enumerate() {
    if item.0 == 0 {  // count == zero
      print!("{:?}", item.1);
    }
    else {  // count > 0
      print!(", {:?}", item.1);
    }
  }
  println!();
  print!("using println!:\n{p:?}");  // p not moved
  println!("\n");

  /*--------------------------------------------------
    Use formatting function that accepts any type
    implementing IntoIterator trait.
    - function defined below
  --------------------------------------------------*/
  show_op("using show_csl(&ar) for array");
  show_csl(&ar); // ar not consumed
  show_op("using show_csl(&v) for Vector");
  show_csl(&v);  // v not consumed
  show_op("using show_csl(&hm) for HashMap");
  show_csl(&hm); // hm not consumed
  show_op("using show_csl(&p) for Point");
  show_csl(&p);  // p not consumed
  println!();

  show_op("using show_csl(ar) for array - copies ar");
  show_csl(ar);  // ar is not consumed as it is a copy type
  show_op("using show_csl(v) for Vector - moves v");
  show_csl(v);   // v is consumed
  show_op("using show_csl(hm) for HashMap - moves hm");
  show_csl(hm);  // hm is consumed
  show_op("using show_csl(p) for Point - moves p");
  show_csl(p);   // p is consumed
}

/* generalize csl strategy #3 */
fn show_csl<C>(c:C)  // consumes c
  where C: IntoIterator, C::Item: Debug
{
  let iter = c.into_iter();
  for (count, val) in iter.enumerate() {
    if count == 0 {
      print!("{:?}", val);
    }
    else {
      print!(", {:?}", val);
    }
  }
  println!();
}









--------------------
  demo_iter()
--------------------













--- array iter using loop ---
1, 2, 3, 4
using println!:
[1, 2, 3, 4]



















--- Vec iter using for-in ---
1, 2, 3, 4
using println!:
[1, 2, 3, 4]

















--- HashMap iter using for-in ---
("one", 1), ("three", 3), ("zero", 0), ("two", 2)
using println!:
{"one": 1, "three": 3, "zero": 0, "two": 2}






















--- Point iter using for-in ---
1.0, 1.5, 2.0, 1.5, 1.0
using println!:
Point { items: [1.0, 1.5, 2.0, 1.5, 1.0] }
















--- using show_csl(&ar) for array ---
1, 2, 3, 4
--- using show_csl(&v) for Vector ---
1, 2, 3, 4
--- using show_csl(&hm) for HashMap ---
("one", 1), ("three", 3), ("zero", 0), ("two", 2)
--- using show_csl(&p) for Point ---
1.0, 1.5, 2.0, 1.5, 1.0


--- using show_csl(ar) for array - copies ar ---
1, 2, 3, 4
--- using show_csl(v) for Vector - moves v ---
1, 2, 3, 4
--- using show_csl(hm) for HashMap - moves hm ---
("one", 1), ("three", 3), ("zero", 0), ("two", 2)
--- using show_csl(p) for Point - moves p ---
1.0, 1.5, 2.0, 1.5, 1.0

2.4 Iteration over custom Point<T, N> Coordinates

A custom type can support iterators in the same way as std::library types. Code in this section illustrates how to do that. The type must provide methods:
iter(), iter_mut() and implement the IntoIterator trait for Point<T, N>, which provides the into_iterator() method.
Usually the type also implements IntoIterator for &Point<T, N> and for &mut Point<T, N>, along with non-mutable and mutable indexers using the std::ops module. See commentary below for motivation.
This block defines a Point<T, N> type that holds a datum items: Vec<T> representing a point in N-dimensional hyperspace. It implements all the features cited in the previous paragraph.
/*-- Point<T, N> --------------------------------
  Point<T, N> declares a Point type holding a
  Vec<T> of coordinate values.
  It implements:
  - new(n)  constructor
  - iter()  returns iterator over items
  - iter_mut() mutates while iterating
  - trait IntoIterator for Point<T, N>
  - trait IntoIterator for &Point<T, N>
  - trati IntoIterator for &mut Point<T, N>
  - immutable and mutable indexing
  Note:
  ---------------------------------------------
  This is a nice example of building a custom
  collection type. It implements methods and
  traits necessary to make a collection behave
  like standard library collections.
  ---------------------------------------------
*/
use std::fmt::*;

#[derive(Debug, Clone)]
pub struct Point<T, const N: usize>
    where T:Debug + Default + Clone
{
    pub items: Vec<T>
}
impl<T, const N:usize> Point<T, N>
    where T:Debug + Default + Clone
{
    /*-- constructor --*/
    pub fn new() -> Point<T, N> {
        Point::<T, N> {
            items: vec![T::default(); N],
        }
    }
    pub fn init(&mut self, v:&Vec<T>) {
      for i in 0..v.len() {
        self.items[i] = v[i].clone();
      }
      for i in v.len()..N {
        self.items[i] = T::default();
      }
    }
    /*-- non-destructive non-mutating iterator */
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.items.iter()
    }
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
        self.items.iter_mut()
    }
}
/*-- implements const indexer -----------------*/
impl<T, const N:usize, Idx> std::ops::Index<Idx> for Point<T, N>
    where
        T:Debug + Default + Clone,
        Idx: std::slice::SliceIndex<[T]>
{
    type Output = Idx::Output;

    fn index(&self, index:Idx) -> &Self::Output {
        &self.items[index]
    }
}
/*-- implements mutable indexer ---------------*/
impl<T, const N:usize, Idx> std::ops::IndexMut<Idx> for Point<T, N>
    where
        T:Debug + Default + Clone,
        Idx: std::slice::SliceIndex<[T]>
{
    fn index_mut(&mut self, index:Idx) -> &mut Self::Output {
        &mut self.items[index]
    }
}
/*-- IntoIterator trait for PointN<T> ---------*/
impl<T, const N:usize> IntoIterator for Point<T, N>
    where T:Debug + Default + Clone
{
    type Item = T;
    type IntoIter = std::vec::IntoIter<Self::Item>;
    fn into_iter(self) -> Self::IntoIter {
        self.items.into_iter()
    }
}
/*-- IntoIterator trait for &Point<T, N> -------------
  - Supports interating elements of Point
  - Point instance is not moved because we use
    Vec::iter() internally
  - a is a required lifetime annotation
*/
use core::slice::Iter;

impl<'a, T, const N:usize> IntoIterator for &'a Point<T, N>
    where T:Debug + Default + Clone
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        self.items.iter()
    }
}
/*-- IntoIterator trait for &mut Point<T, N> ---------
  - Supports mutating elements of Point while
    iterating. No clone used here.
  - Point instance is not moved because we use
    Vec::iter_mut() internally
  - a is a required lifetime annotation
*/
use core::slice::IterMut;

impl<'a, T, const N:usize> IntoIterator for &'a mut Point<T, N>
    where T:Debug + Default + Clone
{
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        self.items.iter_mut()
    }
}

                

Point<T, N> Definition:

Point<T, N> instances are collections of coordinates. This custom type demonstrates how to implement the important methods and traits for collections, making it usable like std library collections. Point<T, N> has a generic parameter T, the type of its coordinates, and N the number of coordinates it uses. A Vec<T> holds its coordinate values, so instances can be moved but not implicitly copied. It declares a derived Clone, asking the compiler to implement that trait for Point. Point Methods: new() -> Point<T, N> constructs a new instance with default values for items. init(&mut self, v:&Vec<T>) fills the item coordinates with values from v. iter(&self) -> impl Iterator<Item = &T> returns items vector iterator. iter_mut(&mut self) -> impl Iterator<Item = &mut T> returns items mutating iterator. Note: impl [trait] in the return position accepts any type that implements the specified trait. non-mutating indexer uses items vector non-mutating indexer. mutating indexer uses items vector mutating indexer. IntoIterator for Point<T, N> implements the IntoIterator trait for Point<T, N>. Calling its trait function p.into_iter() on p ε Point<T, N> returns an iterator over p's items and consumes p, leaving it invalid. IntoIterator for &Point<T, N> implements the IntoIterator trait for &Point<T, N>. Calling its trait function &p.into_iter() on p ε Point<T, N> does not consume p, so it remains valid. IntoIterator for &mut Point<T, N> implements the IntoIterator trait for &mut Point<T, N>. Calling its trait function &mut p.into_iter() on p ε Point<T, N> does not consume p, so it remains valid.

2.5 Point<T, N> Demonstration

/*---------------------------------------------------------
  Demo iteration over coordinate values in Point<T,N>
  - illustrates how to implement iteration for custom
    types, using definitions in points_iter.rs module.
*/
fn demo_point_iteration() {

  show_label("demo point iteration", 30);

  /* uses Point<T,N>::IntoIterator => into_iter() => move */
  let mut p = Point::<i32, 5>::new();
  p.init(&vec![3, 2, 1, 0, -1]);
  show_op("for-in uses p, generating iter from p.into_iter()");
  for item in p {
    print!("{item:?} ");
  }
  // into_iter() consumes v so the next statement is invalid
  // println!("{p:?}");  // v was moved
  println!();

  /* uses &Point<T,N>::IntoIterator => iter() => no move */
  let mut p = Point::<i32, 5>::new();
  p.init(&vec![3, 2, 1, 0, -1]);
  show_op("for-in uses &p, generating iter from &p.iter()");
  println!("original:   {p:?}");
  for item in &p {
    print!("{item:?} ");
  }
  println!();
  println!("after iter: {p:?}");  // v was not moved

  /* uses &mut Point<T,N>::IntoIterator => iter_mut() => no move */
  let mut p = Point::<i32, 5>::new();
  p.init(&vec![-3, -2, -1, 0, 1]);
  show_op("for-in uses &mut p, generating iter from &mut p.iter_mut()");
  println!("original:  {:?}", p);
  for item in &mut p {
    *item += 1;
    print!("{item:?} ");
  }
  println!();
  println!("modified:  {p:?}");  // v was not moved

}






------------------------------
  demo point iteration
------------------------------



--- for-in uses p, generating iter from p.into_iter() ---
3 2 1 0 -1









--- for-in uses &p, generating iter from &p.iter() ---
original:   Point { items: [3, 2, 1, 0, -1] }
3 2 1 0 -1
after iter: Point { items: [3, 2, 1, 0, -1] }







--- for-in uses &mut p, generating iter from &mut p.iter_mut() ---       
original:  Point { items: [-3, -2, -1, 0, 1] }
-2 -1 0 1 2
modified:  Point { items: [-2, -1, 0, 1, 2] }

2.6 Iterator Methods

All Rust iterators provide methods that return another iterator, a collection, or a value. The table below lists a brief selection of methods that appear in the demonstration below the table.
Selection of iterator methods from std::Iter
all<F> (&mut self, f: F) -> bool
where Self: Sized, F: FnMut(Self::Item) -> bool
Tests if every item of the iterator matches a predicate.
any<F> (&mut self, f: F) -> bool
where Self: Sized, F: FnMut(Self::Item) -> bool
Tests if any item of the iterator matches a predicate.
cloned<'a T> (self) -> Cloned<Self>
where T: 'a + Clone', Self: Sized + Iterator<Item = &'a T>"
Consumes an iterator to create an iterator that clones all of its elements.
collect<B> (self) -> B
where B: FromIterator<Self::Item>, Self: Sized
Transforms an iterator into a collection, consuming the iterator.
enumerate (self) -> Enumerate<Self>
where Self: Sized
Consumes iterator to create an iterator which gives current iteration count and the next value
filter<P> (self, predicate: P) -> Filter<Self, P>
where P: FnMut(&Self::Item) -> bool, Self: Sized
Consumes iterator to create an iterator which takes a closure to determine if an item should be yielded.
for_each<F> (self, f: F)
where F: FnMut(Self::Item), Self: Sized
Calls a closure f on each element of an iterator to make in-place changes of items
map<B, F> (self, f: F) -> Map<Self, F>
where F: FnMut(Self::Item) -> B, Self: Sized
Creates an iterator that calls a closure f on each item
Idiomatic Rust code frequently uses more methods, including: by_ref, eq, find, nth, position, rev, skip, step_by, take. Find documentation here: std::Iter.
/*---------------------------------------------------------
  Demonstrate iterator methods
*/
fn demo_methods() {
  show_label("iterator methods", 25);

  show_op("original vector");
  let mut v = vec![1, 2, 3, 2, 1];
  println!("{v:?}");
  show_op("modified using for_each()");
  /* inplace modification of elements of v */
  v.iter_mut().for_each(|item| *item *= *item);
  println!("{v:?}");

  show_op("collect squared items from vec into array");
  let sq:[i32; 5] =
    /* return iterator over squared items from v */
    v.iter().map(|&item| item * item)
      /* collect invokes iterator to load modified elements into sq */
      .collect::<Vec<i32>>().try_into()
      /* display message if collection panics, e.g., fails and terminates */
      .expect("incorrect length");
  println!("{sq:?}");

  show_op("filter out elements larger than 20");
  let filtered: Vec<i32> =
    /* create iterator over filtered elements */
    sq.iter().filter(|&&item| item <= 20)
    /* copy filtered element and collect into Vec */
    .cloned().collect();
  println!("{filtered:?}");
}


                  
-------------------------
  iterator methods
-------------------------
--- original vector ---
[1, 2, 3, 2, 1]

--- modified using for_each() ---
[1, 4, 9, 4, 1]



--- collect squared items from vec into array ---
[1, 16, 81, 16, 1]








--- filter out elements larger than 20 ---
[1, 16, 16, 1]

2.7 Program Structure

The code structure of this demonstration closely resembles earlier Bits, so it is hidden by default.
Code Structure
/*-----------------------------------------------
Bits::rust_iter::main.rs
- demonstrates iteration over collections with
  Rust iterators
- Most collections implement the Rust trait
  IntoIterator which consumes the collection
  to generate an iterator.
- Many also supply functions iter() and mut_iter()
  which return iterators without consuming originial
  collection.
- Demonstrates iteration over arrays, slices,
  Vecs, VecDeques, and custom Point<T, N> type.
-----------------------------------------------*/

#![allow(dead_code)]
#![allow(unused_variables)]

/*-----------------------------------------------
  - Module analysis_iter provides functions
    for type analysis and display.
  - Module points_iter defines type Point<T, N>,
    a point in N-dimensional hyperspace.
*/
use std::collections::*;
mod analysis_iter;
use analysis_iter::*;
mod points_iter;
use points_iter::*;

use std::fmt::*;
use std::cmp::*;

fn demo_loop_iteration() {
  /* code elided */
}
fn demo_for_iteration() {
  /* code elided */
}
fn demo_iter() {
  /* code elided */
}
fn demo_point_iteration() {
  /* code elided */
}
/*-- Begin demonstrations ---------------------*/

fn main() {
  analysis_iter::show_label("Demonstrate Rust Iteration",30);
  
  demo_loop_iteration();
  demo_for_iteration();
  demo_iter();
  demo_point_iteration();

  println!("\nThat's all folks!\n");
}

Program Structure:

This program illustrates how iterators are created and used. It also shows how custom types declare and define their own iterators. This demonstration is partitioned into three modules: - main.rs (this file) a sequence of demonstration functions, each focused on one type of syntax and the main function that controls processing - points_iter.rs defines custom type Point<T, N> - analysis_iter.rs defines functions for type analysis and display Blocks with left and right panels illustrate each function invoked here, shown above this block. The left panel shows code and the right panel shows output, separated by a splitter-bar that reveals content hidden in the default display.

3.0 Build


            C:\github\JimFawcett\Bits\Rust\rust_iter
              > cargo run
                Compiling rust_iter v0.1.0 (C:\github\JimFawcett\Bits\Rust\rust_iter)
                Finished dev [unoptimized + debuginfo] target(s) in 0.50s
              C:\github\JimFawcett\Bits\Rust\rust_iter
              >

4.0 VS Code View

The code for this demo lives in github.com/JimFawcett/Bits. Click the Code dropdown to clone the repository of demo code to your local drive. Then open any example, in any of the languages, in VS Code. Here, we do that for Rust\rust_iter. Figure 1. VS Code IDE - Debug Rust Iter

5.0 References

Reference Description
RustBite_Iterators RustBite on Iterators and Adapters
Rust Story E-book with seven chapters covering most of intermediate Rust
Rust Bites Relatively short feature discussions
std::Iter Library documentation for all of the standard methods. These are provided by any type that implements the Iterator trait.