0

I am trying to implement a filter function which receives an iterator to a vector and returns an iterator with the filter. Is there any way by which I don't link the lifetime of the iterator to the struct? I am able to make it work by making lifetime of iterator depend on the struct but that is not what I intend to do.

Here is a simplified code:

struct Structure {
    low: i32,
}

impl Structure {
    pub fn find_low<'a>(
        &mut self,
        packets: impl Iterator<Item = &'a i32>,
    ) -> impl Iterator<Item = &'a i32> {
        packets.filter(|packet| **packet < self.low)
    }

    pub fn new() -> Self {
        Structure { low: 10 }
    }
}

fn main() {
    let strct = Structure::new();
    let vec = [1, 2, 3, 11, 12, 13];
    let mut it = strct.find_low(vec.iter());
    assert_eq!(it.next().unwrap(), &vec[0]);
}

By doing so, I get an error

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
 --> src/main.rs:9:10
  |
7 |         &mut self,
  |         --------- hidden type `Filter<impl Iterator<Item = &'a i32>, [closure@src/main.rs:10:24: 10:52]>` captures the anonymous lifetime defined here
8 |         packets: impl Iterator<Item = &'a i32>,
9 |     ) -> impl Iterator<Item = &'a i32> {
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
  |
9 |     ) -> impl Iterator<Item = &'a i32> + '_ {
  |                                        ++++

Playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • This is possibly a duplicate of https://stackoverflow.com/q/67901675 ([Applied to your code](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bf6c8a3d030cddaed86f87404ab0db52)) – E_net4 Apr 06 '22 at 16:44
  • 1
    Your returned iterator references `self.low`, which means that it **should** incorporate the lifetime of `self`. You could [copy the value of `low` into the closure](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0281a359295d09994bf88abb21127284). – Shepmaster Apr 06 '22 at 16:45

1 Answers1

1

Yes, there is a way not to link the lifetime of the returned iterator to that of the reference to self: you need to move the data the filtering closure needs into the closure so that it doesn't reference it. To accomplish this, copy self.low into a local variable and move it into the closure.

Once you fix this, you will uncover a second problem: your main() as written can't invoke strct.find_low() as strct is not declared mut -- but it shouldn't need to be. find_low needlessly takes self as a mutable reference, when an immutable reference will do. Replace &mut self with &self.

    pub fn find_low<'a>(
        &self,
        packets: impl Iterator<Item = &'a i32>,
    ) -> impl Iterator<Item = &'a i32> {
        let low = self.low;
        packets.filter(move |packet| **packet < low)
    }

(Playground)

An alternative to moving a copy of self.low into the closure is to restrict the lifetime of &self to include 'a as well, though this does link the lifetime of the returned iterator to that of Structure.

    pub fn find_low<'a>(
        &'a self,
        packets: impl Iterator<Item = &'a i32>,
    ) -> impl Iterator<Item = &'a i32> {
        packets.filter(move |packet| **packet < self.low)
    }

(Playground)

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • This works for the example posted. However, in the real code I am working with a redis connection inside the filter. Redis needs a mutable copy of connection (which is stored in the object) to do the SET operation. Hence, unable to create a copy. – Richa Jain Apr 06 '22 at 17:40
  • @RichaJain Then you will need the second approach I gave in my answer, which requires that `*self` outlive the returned iterator, or else you'd need some way to clone `Structure` and have the closure take ownership of the clone. – cdhowie Apr 06 '22 at 17:42
  • Cannot do either since redis connection is a lazy_static mutex (so cannot clone), I would like to drop the redis keys in the end which is interfering with the lifetime – Richa Jain Apr 06 '22 at 17:54
  • @RichaJain Then you'll have to post a new question that properly illustrates the new problem you're running into. – cdhowie Apr 06 '22 at 18:02
  • Sure, let me do that – Richa Jain Apr 08 '22 at 00:40