How to make the filter work?

I'm trying to iterate over an &mut u8 type , and tried with the following 2 , none of them works. Help me please.

fn main() {
  vec![1,2,3]
  .iter_mut()
  .filter(|x|(|x:&mut u8|true)(x)); // 1 type mismatch
}
fn main() {
  vec![1,2,3]
  .iter_mut()
  .filter_map(|x|(|x:&mut u8|Some(x))(x)); // 2 have lifetime issue
}

The following code compiles:

fn main() {
 vec![1,2,3]
  .iter_mut()
  .filter_map(|x| (|x| Some(x))(*x)  ); 
}

but I want the filtered one a collection of &mut u8 instead of u8

(1) doesn't work because filter() gives the callback only a reference, &T, so the type of x should be &&mut u8.

As for (2), this is really interesting - I was able to reduce it to the following:

|x: &'_ mut u8| -> &'_ mut u8 { x };

And the compiler complains

error: lifetime may not live long enough
 --> src/main.rs:2:37
  |
2 |     |x: &'_ mut u8| -> &'_ mut u8 { x };
  |         -              -            ^ returning this value requires that `'1` must outlive `'2`
  |         |              |
  |         |              let's call the lifetime of this reference `'2`
  |         let's call the lifetime of this reference `'1`

Playground

It looks like something breaks with closure inference. But I have no idea what.

I'll leave that to someone with more expertise than me to explain what is happening here.

1 Like

Ok, maybe try:

fn main() {
  let mut b = vec![1,2,3];
  let c: Vec<&mut u8> = b.iter_mut()
    .filter_map(|x| {
      (|x| Some(x))(x)
    })
    .collect(); // 2 have lifetime issue

}

I put it in a Vec c just to show that it is indeed a collection of mutable references, but you can pick any compatible collection you like.

(I don't think there is) really a way to make this work without putting the original collection b into a variable because its lifetime ends when it goes out of scope (even though iter_mut is by reference, the vec is no longer in scope after that in the original example)

it's fun if I give x an type , it will not work

  let c: Vec<&mut u8> = b.iter_mut()
    .filter_map(|x| {
-      (|x| Some(x))(x)
+      (|x:&mut u8| Some(x))(x)
    })
}

It might not be possible due to the use of a closure and not a function. I don't know why it's necessary to do it because the original post provides no specifics, but perhaps start there.

Edit: Whoops here's a link:
https://github.com/rust-lang/rust/issues/86921

2 Likes

thank you. It's time to learn lifetime from the ground :blush:

1 Like

I'll use function as an workaround.

fn main() {
  let mut v = vec![1,2,3];
  let v : Vec<&mut u8> = 
    v.iter_mut()
    .filter_map(|x|test(x))
    .collect();

  fn test(x:&mut u8)->Option<&mut u8> {
    *x=1;
    Some(x)
  }
}

Incidentally you can just do

   let v : Vec<&mut u8> = 
     v.iter_mut()
-    .filter_map(|x|test(x))
+    .filter_map(test)
     .collect();
2 Likes

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.