Passing a returned iterator trait object to a function


#1

Hi

I have a function that returns an iterator trait object, i.e. something like

fn foo<'a>(...) -> Result<Box<Iterator<Item = SomeType> + 'a + Send>>

I’m trying to use the it to return a stream in a gRPC service. I’m using grpc-rust. To do this, I have to construct a StreamingResponse.

However, the struct and methods are written using 'static lifetimes for the iterator. For example, the iter method has the following signature:

pub fn iter<I>(iter: I) -> StreamingResponse<T>
        where I : Iterator<Item=T> + Send + 'static

Is there a way to reconcile the lifetimes so that I can can pass the result of foo() to StreamingResponse::iter? Do I have to change foo to return a concrete iterator, instead of a trait object?

Thanks,
Andre


#2

It should work as is. The signature of foo says the caller gets to decide what 'a is, so the caller can pick 'a = 'static and get back a Box<Iterator<Item = SomeType> + 'static + Send>. Playground


#3

So it seems my problem is actually that the iterator comes from a vector stored in a BTreeMap in my struct, and this is causing trouble with the lifetimes of the references to self… trying to fix that…


#4

So this is the code in question:

pub struct MyMap {
    map: Arc<Mutex<BTreeMap<String, Vec<SomeType>>>>,
}

impl MyMap {
    fn foo<'a>(
        &self,
        key: String,
        start: usize,
        len: usize,
    ) -> Result<Box<Iterator<Item = SomeType> + 'a + Send>> {
        let map = self.map.lock().unwrap();
        match store.get(&key) {
            Some(vector) => {
                let iter = vector.clone().into_iter().skip(start).take(len);
                Ok(Box::new(iter))
            }
            None => Err(...),
        }
    }
}

This actually works… the problem I had was that I had used &'a self in the foo signature to try to ensure the returned iterator items would survive long enough… but I think that didn’t work because I can’t return references to something protected by a mutex, so I added the clone() call but the 'a remained. Simply removing it fixed my issue.