If my understanding is correct, when I have a struct MyStruct, I can do both of these below:
impl IntoIter for MyStruct
impl <'a> IntoIter for &'a MyStruct
to get me both a consuming and a non consuming iterators so that I can do:
let dataset :MyStruct = out_of_thin_air();
//borrow dataset immutably
for item in &dataset {
//do something
}
//mutable borrow
for item in dataset {
//do something else
}
I want the same behaviour from an object returned by a method which will be part of a Trait, like:
pub trait DataSource {
get_data(&self) -> T where T: Please_Help
}
Once I impl DataSource for MyStruct and MyAnotherStruct, I can do:
let another_dataset: [MyAnotherStruct or MyStruct] = somehow();
// non consuming iteration
for item in &(another_dataset.get_data()) {
//do something
}
// consuming iteration
for item in another_dataset.get_data() {
//do something else
}
Is it possible to have one get_data() in a trait to return an object that can impl IntoIter with and without consuming the object ?
As @kornel mentioned, you can follow the same pattern as Vec does, where depending on whether you have an owned value or borrowed, you get a certain type of IntoIterator impl. So something like:
trait DataSource {
type Iter: IntoIterator; // maybe use another associated type for the item type yielded by the iterator
fn get_data(self) -> Self::Iter; // note that you need to take `self`, not `&self`
}
struct MyStruct(Vec<i32>);
impl DataSource for MyStruct {
type Iter = std::vec::IntoIter<i32>;
fn get_data(self) -> Self::Iter {
self.0.into_iter()
}
}
impl<'a> DataSource for &'a MyStruct {
type Iter = std::slice::Iter<'a, i32>;
fn get_data(self) -> Self::Iter {
self.0.iter()
}
}
So now once you have an instance of MyStruct (or MyAnotherStruct), you can decide whether to use their owned or borrowed IntoIterator versions.
@vitalyd Thank you very much for the detailed answer. I just have one more concern:
In DataSource trait, we have the bound IntoIterator for type Iter. But in impl <'a> DataSource for &'a MyStruct, the Iter type is std::slice::Iter<'a, i32>. Looking at Iter in std::slice - Rust, this struct does not implement IntoIterator, but implements Iterator. Isnt this violating the trait bound ?