Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
939 views
in Technique[技术] by (71.8m points)

rust - Why does this simple closure fail while the other two functions succeed?

I've constructed a closure example that I can't get to work, nor can I find any reason why it shouldn't work. Why does it fail to compile on the last closure?

Playground

struct S {}

fn filter<P>(predicate: P)
where
    P: Fn(&S) -> bool,
{
    predicate(&S {});
}

fn main() {
    // this works
    filter(|_s| true);

    // this also works
    fn cb1(_s: &S) -> bool {
        true
    }
    filter(cb1);

    // but this doesn't work
    let cb2 = |_s| true;
    filter(cb2);
}

Output:

error[E0631]: type mismatch in closure arguments
  --> /tmp/closure.rs:19:5
   |
18 |     let cb2 = |_s| true;
   |               --------- found signature of `fn(_) -> _`
19 |     filter(cb2);
   |     ^^^^^^ expected signature of `for<'r> fn(&'r S) -> _`
   |
note: required by `filter`
  --> /tmp/closure.rs:3:1
   |
3  | fn filter<P>(predicate: P) where P: Fn(&S) -> bool,
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `for<'r> <[closure@/tmp/closure.rs:18:15: 18:24] as std::ops::FnOnce<(&'r S,)>>::Output == bool`
  --> /tmp/closure.rs:19:5
   |
19 |     filter(cb2);
   |     ^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
note: required by `filter`
  --> /tmp/closure.rs:3:1
   |
3  | fn filter<P>(predicate: P) where P: Fn(&S) -> bool,
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

From following Type mismatches resolving a closure that takes arguments by reference and How to declare a lifetime for a closure argument? it appears the solution is to change:

fn filter<P>(predicate: P)
where
    P: Fn(&S) -> bool,
{
    predicate(&S {});
}

to

fn filter<'a, P>(predicate: P)
where
    P: Fn(&'a S) -> bool,
{
    predicate(&S {});
}

Though I'm not sure why. It seems to be related to inferred lifetimes when a closure is specified inline vs when it is stored in a variable and used later. But it's unclear why &S needs an 'a lifetime, when &S is not a result that is returned. If you understand this, please explain in a comment.

Though this question is "solved", the trimmed-down failure case posted originally does not actually help my true problem, because I cannot edit the source of the code I am having trouble with https://docs.rs/walkdir/2.2.9/walkdir/struct.IntoIter.html#method.filter_entry

The issue manifested when I tried to pass a stored callback into the filter_entry method. The solution would be to put in explicit lifetimes in the filter_entry signature, as described earlier in this post, but you can only do that if you want to edit the third party code. I think unfortunately the answer for that particular problem is "you can't use a stored closure with filter_entry"


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...