Naive Iterator question

My apologies in advance if this is obvious and I simply missed it.
I have a number of cases in the toy program I am using to learn Rust where I have a struct (say S), with a field (say f), whose type is Vec where C is some content struct. (in one case, just a usize; in other cases somewhat more.) I want to have a method on S that returns an iterator over the field F. I tried what I thought was the obvious definition of returning self.f.iter(). And the compiler, presuambly quit ecorrectly, complained that I was trying to return an internal value.
Do I need to clone(or copy?) f before I invoke .iter()? I am quite happy if the iterator produces only immutable references to the innards.
Thanks,
Joel

I such situation cloning is the cause of the problem. Returning of a by-reference iterator could work only if you didn't try to iterate over a clone.

Rust's references aren't just an indirection. They are first and foremost loans - a view into data stored elsewhere. Loans are temporary[1] and forbidden from ever leaving the scope they're borrowing from.

That iterator from iter() is by design borrowing the collection it iterates over.

If you create a new object (such as a clone of a field), the object has to be stored somewhere, as otherwise it will be destroyed automatically at the end of the statement. If you store it in a variable, it will be destroyed when the variable goes out of scope.

So return field.clone().iter() can never work, because it makes a new object, borrows it for iteration, then destroys the object that wasn't saved anywhere, and then tries to return iterator for an object that doesn't exist any more.

References will never make anything live longer. It's always the other way - your code must first ensure that objects are stored in an appropriate place for long enough for the references you want to use.

Without clone, self.field.iter() can work, because the field is already stored in self, and when your method gets a borrowed &self, it already knows that self outlives the method call, so the field will too.


There's into_iter() that doesn't borrow the collection, and instead takes exclusive ownership of it.

You can't use self.field.into_iter() because it's not possible for self and an iterator to both have exclusive ownership of the same vec.

But in that case you can do return self.field.clone().into_iter(), because the owning iterator will store the cloned vec inside of itself, and the caller will store the iterator, so the cloned vec will have a place to live and won't get destroyed when the function returns.


  1. except leaked memory or hardcoded constants, but these are uninteresting exceptions â†Šī¸Ž

3 Likes

Thanks. clone().into_iter() took care of the problem. I suspected clone() by itself wouldn't do the job, which is why I asked.
Yours,
Joel

For Vec<usize> where the items are cheap to copy, another option is self.field.iter().copied().

This borrows the field using a by-reference iterator, but then the iterator copies each item just before returning it. It's cheaper than creating a copy of the whole Vec beforehand.

Thanks. I'll have t consider ".copied()".
Yours,
Joel