I have the following code, how can I return a Iterator from the compute
method?
pub trait BasicVec {
fn compute(&self, part: u32) -> Box<Iterator<Item=i32>>;
}
pub struct ParaVec<'a> {
name: &'static str,
data: &'a Vec<i32>,
}
impl<'a> BasicVec for ParaVec<'a> {
fn compute(&self, part: u32) -> Box<Iterator<Item=i32>> { // error
Box::new(self.data.iter())
}
}
I know the compiler can not infer enough information about self.data.iter()
, but how can I give more hint to the compiler? and is there any way to express the return iterator in a generic way, such as if the data is Vec<T>
?
1 Like
There are 2 things to fix there. First, self.data.iter()
is an iterator over &i32
rather than i32
. We can change this to self.data.iter().cloned()
to fix that. Second, a Box<Iterator<Item = i32>>
implies a 'static
lifetime for the iterator, where in this case the lifetime is limited. The most straightforward way to deal with that is to add a lifetime annotation to compute
pub trait BasicVec {
fn compute<'a>(&'a self, part: u32) -> Box<Iterator<Item=i32> + 'a>;
}
pub struct ParaVec<'a> {
name: &'static str,
data: &'a Vec<i32>,
}
impl<'a> BasicVec for ParaVec<'a> {
fn compute<'b>(&'b self, part: u32) -> Box<Iterator<Item=i32>+ 'b> {
Box::new(self.data.iter().cloned())
}
}
4 Likes
Thanks, as you pointed out, I need to use the cloned()
method, so I change to the following ways to avoid the clone.
pub trait BasicVec {
fn compute<'a>(&'a self, part: u32) -> Box<Iterator<Item=&i32> + 'a>;
}
pub struct ParaVec<'a> {
name: &'static str,
data: &'a Vec<i32>,
}
impl<'a> BasicVec for ParaVec<'a> {
fn compute<'b>(&'b self, part: u32) -> Box<Iterator<Item=&i32>+ 'b> {
Box::new(self.data.iter())
}
}
That works too, but is there a reason you want to avoid calling cloned()
? Turning an &i32
into a i32
is not an expensive operation.
I want the data structure to be generic later, the data
to be Vec<T>
.