Returning Boxed Iterator Requires an Approriate Lifetime

I have a method as below:

    pub fn filter_names(&self, query: &str, starts_with: bool) -> Box<dyn Iterator<Item = &str>> {
        debug!("Filtering code names...");
        trace!("query: {}", query);
        trace!("starts with: {}", starts_with);

        debug!("Generating code iterator...");
        Box::new(self
            .codes
            .iter()
            .filter(|c| match starts_with {
                true => {
                    let do_filter = c.name.starts_with(query);
                    trace!("`{}` starts with `{}`: {}", c.name, query, do_filter);
                    do_filter
                }
                false => {
                    let do_filter = c.name.contains(query);
                    trace!("`{}` contains `{}`: {}", c.name, query, do_filter);
                    do_filter
                }
            })
            .map(|c| {
                debug!("Mapping `{}` to &str...", c.name);
                c.name
            }))
    }

I do not like to collect it and leave collecting to library users. I don't know if this is a valid approach in Rust, though it is in Python. Lazy evaluation matters in cases which the performance is desired. It is the logic behind.

This code, however, fails on iter() call on self saying:

cannot infer an appropriate lifetime for autoref due to conflicting requirements

note: but, the lifetime must be valid for the static lifetime...
note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = &str> + 'static)>`
         found  `std::boxed::Box<dyn std::iter::Iterator<Item = &str>>`rustc(E0495)

Why does compiler expect that the return of filter_names is supposed to be 'static in this case? What is a viable solution to this issue? AFAIK, 'static lives as long as the program lives, which, I don't think, is not desirable because I do not want this Iterator trait object to live as long as the program runs, I want it to be called and let the Iterator trait object live as much as the scope that calls it needs it.

Thanks in advance.


Environment

  • Rust 1.43.1

Default trait object bounds says that Box<dyn Trait> is short for Box<dyn Trait + 'static>

You can override this by specifying a non-static lifetime, like this:

pub fn filter_names<'a>(&'a self, query: &str, starts_with: bool)
    -> Box<dyn Iterator<Item = &'a str> + 'a>

I think you can also use lifetime elision to shorten this to:

pub fn filter_names(&self, query: &str, starts_with: bool)
    -> Box<dyn Iterator<Item = &str> + '_>
2 Likes

For the fully qualified version, I think query may also need a lifetime bound, because filter’s closure retains a reference to it:

pub fn filter_names<'a>(&'a self, query: &'a str, starts_with: bool)
    -> Box<dyn Iterator<Item = &'a str> + 'a>
2 Likes

Good point. You might also need to use move closures so they can outlast the local variables they capture.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.