Dmitry Mantis
Dmitry Mantis

Reputation: 184

How to implement iterator trait over wrapped vector in Rust?

Having code like

#[derive(Debug)]
struct BinaryVec {
    vec: Vec<u8>,
}

impl BinaryVec {
    fn empty() -> BinaryVec {
        BinaryVec { vec: Vec::new() }
    }

    fn push(&mut self, bit: u8) {
        self.vec.push(bit);
    }
}

I'd like to be able to iterate over the structure's vector without making it public. For example, to call it like:

let bin_vec = BinaryVec::empty();
bin_vec.push(1);
bin_vec.push(0);
bin_vec.push(1);
for el in bin_vec.iter() { 
    // do something with 1,0,1 elements 
}

But I see that Iterator trait requires only next method which assumes the saved iter state in the structure.

Is there any way to directly pass vec iter through the higher level struct in Rust without adding new state related fields to the struct?

Upvotes: 12

Views: 4320

Answers (2)

SOFe
SOFe

Reputation: 8224

Vec<T> itself does not implement Iterator either. However, it implements IntoIterator in three ways:

  • impl<T> IntoIterator for Vec<T>: you can write for item in vec, and each item will take a T by value. This consumes the vector.
  • impl<T> IntoIterator for &'_ [T] (where &Vec<T> derefs to &[T]): you can write for item in &vec, and each item will take a &T.
  • impl<T> IntoIterator for &'_ mut [T] (where &mut Vec<T> derefs to &mut [T]): you can write for item in &mut vec, and each item will take a &mut T.

You probably wanted to implement these for your wrapper as well:

impl IntoIterator for BinaryVec {
  type Item = u8;
  type IntoIter = <Vec<u8> as IntoIterator>::IntoIter; // so that you don't have to write std::vec::IntoIter, which nobody remembers anyway

  fn into_iter(self) -> Self::IntoIter {
    self.vec.into_iter()
  }
}

// We deref to slice so that we can reuse the slice impls
impl Deref for BinaryVec {
  type Output = [u8];

  fn deref(&self) -> &[u8] {
    &self.vec[..]
  }
}
impl DerefMut for BinaryVec {
  type Output = [u8];

  fn deref_mut(&mut self) -> &mut [u8] {
    &mut self.vec[..]
  }
}

Note that implementing IntoIterator for &mut [T] is not trivial (you need to use stuff methods split_first_mut if you don't want to write unsafe code), so better reuse the implementation from slices.

Upvotes: 9

NivPgir
NivPgir

Reputation: 133

Actually, to call it as you described, you don't need to implement Iterator for it. You just need to return the iterator of the inner vec:

impl BinaryVec {
     ...
     fn iter(self: &Self) -> impl Iterator<Item=u8>{
           self.vec.iter()
     }
}

Note that even the standard Vec doesn't implement Iterator, It's the struct that iter returns that implements it.

Upvotes: 10

Related Questions