2

Let's say I have a struct that has a collection, such as a Vec as one of its data members:

struct MyCollection {
    data: Vec<i32>
}

I want the user of MyCollection to be able to iterate over its data without direct access to the Vec itself, like so:

let x = MyCollection{data:vec![1, 2, 3, 4, 5]};

for i in &x {
    //...
}

However, I'm struggling with implementing the necessary Trait IntoIterator for the non-consuming version with &x. I have successfully implemented the consuming version:

impl std::iter::IntoIterator for MyCollection {
    type Item = i32;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        return self.data.into_iter();
    }
}

However, this is only usable as follows:

for i in x {
    println!("{:?}", i);
}

which consumes x. Cloning the data is possible, but quite expensive, so I'd like to avoid that.

Here is what I have so far for the non-consuming version, which I based on the source implementation of std::vec::Vec:

impl<'a> std::iter::IntoIterator for &'a MyCollection {
    type Item = &'a i32;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        return self.data.into_iter();
    }
}

which produces the following compile error:

error: mismatched types
error: expected &i32, found i32
note: expected type `std::vec::IntoIter<&i32>`
   found type `std::vec::IntoIter<i32>`
error: expected `std::vec::IntoIter<&i32>` because of return type

I have also tried removing the &'a of the type Item since in my case, the elements of data are Copyable, but this yields the following:

error: cannot move out of `self.data` which is behind a shared reference
error: move occurs because `self.data` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait

I understand the function wants an IntoIter of a vector to references, but I'm unsure how to give it one efficiently. I'm new to Rust, so I'd much appreciate some clarity on the concern. Bonus points if you can also tell me how to create a mutable iterator for write access in the same fashion.

1
  • "Bonus points if you can also tell me how to create a mutable iterator for write access in the same fashion." haha, I will let you that as exercise so Commented Jan 17, 2020 at 2:25

1 Answer 1

3

First, you should use slice type, your user shouldn't have to know that you inner type is vector. Then, your problem is that you must not use IntoIter type, but Iter type directly.

Simple example:

struct MyCollection {
    data: Vec<i32>,
}

impl<'a> std::iter::IntoIterator for &'a MyCollection {
    type Item = <std::slice::Iter<'a, i32> as Iterator>::Item;
    type IntoIter = std::slice::Iter<'a, i32>;

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

fn main() {
    let x = MyCollection {
        data: vec![1, 2, 3, 4, 5],
    };

    for i in &x {
        println!("{}", i);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.