Why does Rust closure not follow the lifetime elision rule? [duplicate] - rust

fn main() {
let _ref_in_ref_out = |var: &i64| var;
}
This does not compile:
error: lifetime may not live long enough
--> src/main.rs:2:39
|
2 | let _ref_in_ref_out = |var: &i64| var;
| - - ^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 i64
| let's call the lifetime of this reference `'1`
Apparently the compiler infers two different lifetimes (for the argument and the return type), instead of it being the same.
Is it possible to write a closure so that the input lifetime is the same as the output lifetime?
Something like
fn ref_in_ref_out<'a> (var: &'a i64) -> &'a i64 { var }
but as a closure

Lifetime elisions rules do not apply to closures, neither can you explicitly specify lifetimes for closures. There are several ways to make this code work, though.
The easiest solution is to simply omit the type annotations and let the compiler infer everything:
let ref_in_ref_out = |var| var;
let i: i64 = 42;
ref_in_ref_out(&i);
Alternatively, it's actually fine to specify the return type. This compiles:
let _ref_in_ref_out = |var| -> &i64 { var };
Yet another option for the case that your closure does not close over any local variables is to convert it to a function pointer, since lifetime elision rules apply to function pointers:
let ref_in_ref_out: fn(&i64) -> &i64 = |var| var;
And finally the most general solution is to use a helper function to apply a function trait bound to your closure:
fn constrain_closure<F: Fn(&i64) -> &i64>(f: F) -> F {
f
}
let _ref_in_ref_out = constrain_closure(|var| var);

I've just found out a way to solve this issue, but It'd be great if there is an easier solution:
fn infer_lifetime<'a, T: 'a, F: Fn(&'a T) -> &'a T>(f: F) -> F {
f
}
fn main() {
let _ref_in_ref_out = infer_lifetime(|var: &i64| var);
}

Related

the parameter type may not live long enough (again?) (in closure)

In trying to compile the code
fn make<DomainType>(foo: fn(DomainType) -> ()) -> Box<dyn Fn(DomainType) -> ()> {
let foo_clone = foo.clone();
let bar = move |input: DomainType| {foo_clone(input)};
Box::new(bar)
}
fn main() {}
The compiler gives
error[E0310]: the parameter type `DomainType` may not live long enough
--> src/main.rs:4:5
|
4 | Box::new(bar)
| ^^^^^^^^^^^^^ ...so that the type `[closure#src/main.rs:3:15: 3:58]` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
1 | fn make<DomainType: 'static>(foo: fn(DomainType) -> ()) -> Box<dyn Fn(DomainType) -> ()> {
| +++++++++
For more information about this error, try `rustc --explain E0310`.
I have been reading through similar questions
Parameter type may not live long enough?
and
The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
But in both of those examples, the boxed trait is what needs the added lifetime. In this case it's apparently just the DomainType of the closure trait. I'm quite baffled what to make of this.
My understanding of lifetime variables in function definitions is that they connect the lifetime of the returned type (which I can understand is implicitly static here, or at least the thing inside the box is) to those (perhaps elided) lifetimes of the function parameters. But no function parameter here is a DomainType.
DISCLAIMER: This question goes very deep into Rust compiler specifics, and I'm not 100% sure about everything I say here. Take everything with a grain of salt.
The problem here is that Box<T> means that T is 'static if no lifetime is annotated.
A generic, however, does not mean that. A generic could contain any kind of lifetime. To match the two, you need an explicit lifetime annotation.
Solution 1
You could annotate 'static to the generic, like this:
fn make<DomainType: 'static>(foo: fn(DomainType)) -> Box<dyn Fn(DomainType)> {
Box::new(foo)
}
That, however, would create problems if you do actually encounter the case where the generic carries a lifetime:
fn my_func(x: &str) {
println!("my_func: {}", x);
}
fn main() {
let x = "abc".to_string();
let f = make(my_func);
f(&x);
}
error[E0597]: `x` does not live long enough
--> src/main.rs:13:7
|
13 | f(&x);
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `x` is borrowed for `'static`
14 | }
| - `x` dropped here while still borrowed
Solution 2
The proper way here is to solve the initial mismatch by telling the compiler that the lifetimes attached to the generic match the lifetimes contained in the Box.
Like this:
fn make<'a, DomainType: 'a>(foo: fn(DomainType)) -> Box<dyn Fn(DomainType) + 'a> {
Box::new(foo)
}
And it now works:
fn my_func(x: &str) {
println!("my_func: {}", x);
}
fn main() {
let x = "abc".to_string();
let f = make(my_func);
f(&x);
}
my_func: abc
Problems
There are still problems with this. I'm unsure how/if they are solvable, though.
The problem is that the resulting Box object will always be bound to a specific lifetime. Look for example at this:
fn make<'a, DomainType: 'a>(foo: fn(DomainType)) -> Box<dyn Fn(DomainType) + 'a> {
Box::new(foo)
}
fn my_func(x: &str) {
println!("my_func: {}", x);
}
fn make2() -> Box<dyn Fn(&str)> {
Box::new(|x| println!("closure: {}", x))
}
fn main() {
let x = "abc".to_string();
let f = make(my_func);
let f2 = make2();
let fs = [f2, f];
}
error[E0308]: mismatched types
--> src/main.rs:19:19
|
19 | let fs = [f2, f];
| ^ one type is more general than the other
|
= note: expected trait object `dyn for<'r> Fn(&'r str)`
found trait object `dyn Fn(&str)`
f2 here takes all objects that can be borrowed. f only takes objects that all can be borrowed with the same lifetime, as 'a resolves when make is called, not when f is executed.
Another example is this:
fn make<'a, DomainType: 'a>(foo: fn(DomainType)) -> Box<dyn Fn(DomainType) + 'a> {
Box::new(foo)
}
fn my_func(x: &str) {
println!("my_func: {}", x);
}
fn make2() -> Box<dyn Fn(&str)> {
Box::new(|x| println!("closure: {}", x))
}
fn main() {
let f = make(my_func);
let f2 = make2();
{
let x = "abc".to_string();
f2(&x); // Works
f(&x); // Fails to compile
}
}
error[E0597]: `x` does not live long enough
--> src/main.rs:20:11
|
20 | f(&x); // Fails to compile
| ^^ borrowed value does not live long enough
21 | }
| - `x` dropped here while still borrowed
22 | }
| - borrow might be used here, when `f` is dropped and runs the destructor for type `Box<dyn Fn(&str)>`
|
= note: values in a scope are dropped in the opposite order they are defined
I don't think this is solvable, though. I think generics can't carry generic lifetimes, they can only carry specific lifetimes. And said specific lifetime gets resolved at the point where make() is called.
Although a proper explanation would require someone with a deeper Rust compiler understanding than me. If something like this exists, I'd be interested in it as well. (something like DomainType: for<'a> or similar)
I can see that one of the example's output says it would require a dyn for<'r> Fn(&'r str). I don't know, however, if something like this is annotatable by hand or if it's something internal to the compiler. But that would be what is required - instead of Box<dyn Fn(DomainType) + 'a>, we would need something like Box<dyn for <'r> Fn(DomainType + 'r)>. Again, I don't know if/how this is annotatable, and if it is, I'd also be interested in it.
Could Higher Rank Trait Bounds be what you're looking for?
fn make<F, DomainType>(foo: F) -> Box<dyn Fn(DomainType)>
where
for<'r> F: Fn(DomainType) + Clone + 'r
{
let foo_clone = foo.clone();
let bar = move |input: DomainType| {foo_clone(input)};
Box::new(bar)
}
If the purpose of the function is to consume a closure and return it in a Box, I don't think you need the Clone trait. In fact, it doesn't even need to be nested in a new closure. Just directly box it.
fn make<F, DomainType>(foo: F) -> Box<dyn Fn(DomainType)>
where
for<'r> F: Fn(DomainType) + 'r
{
Box::new(foo)
}
Unless you want to pass in a reference to a closure that doesn't get consumed:
fn make<F, DomainType>(foo: &F) -> Box<dyn Fn(DomainType)>
where
for<'r> F: Fn(DomainType) + Clone + 'r
{
Box::new(foo.clone())
}

Why the mutable reference parameter of a closure doesn't outlive the function call?

I'm using cssparser crate to parse some CSS code. I would like to create a closure that is able to parse a type function. As a first step, I create a very simple code that way:
use cssparser::{Parser, ParserInput};
fn main() {
let input_string = "type(\"image/png\")";
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let parse_type = |p: &mut Parser| {
p.expect_function_matching("type")?;
Ok("OK")
};
let res = parse_type(&mut parser);
}
I got the following error:
error[E0282]: type annotations needed for the closure `fn(&mut Parser<'_, '_>) -> std::result::Result<&str, _>`
--> src/main.rs:9:43
|
9 | p.expect_function_matching("type")?;
| ^ cannot infer type of error for `?` operator
|
= note: `?` implicitly converts the error value into a type implementing `From<BasicParseError<'_>>`
As read in this answer, I added the return type of my closure:
let parse_type = |p: &mut Parser| -> Result<&str, cssparser::BasicParseError> {
p.expect_function_matching("type")?;
Ok("OK")
};
I still have an error I don't understand:
error: lifetime may not live long enough
--> src/main.rs:9:9
|
8 | let parse_type = |p: &mut Parser| -> Result<&str, cssparser::BasicParseError> {
| - ---------------------------------------- return type of closure is std::result::Result<&str, BasicParseError<'2>>
| |
| has type `&mut Parser<'1, '_>`
9 | p.expect_function_matching("type")?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
Apparently '1 is release before '2. How can it be the case as the parameter of my closure is a reference? It should still be alive after the call to my closure, right?
I tried to explicitly annotate the lifetime of my objects but I wasn't able to find the correct way to do it; I always have an "undeclared lifetime" error. For instance:
let parse_type = |p: &mut Parser<'i, '_>| -> Result<&str, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
};
Unfortunately, closures can't declare lifetime arguments, which will be required to communicate the proper lifetimes for this function. Moving it out to a function gives a better error:
use cssparser::{Parser, ParserInput};
fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
p.expect_function_matching("type")?;
Ok("OK")
}
fn main() {
let input_string = "type(\"image/png\")";
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let res = parse_type(&mut parser);
}
error[E0106]: missing lifetime specifier
--> src\main.rs:3:41
|
3 | fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
| ----------- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `p`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
3 | fn parse_type<'a>(p: &'a mut Parser) -> Result<&'a str, cssparser::BasicParseError> {
| ^^^^ ^^^^^^^^^^^^^^ ^^^
error[E0106]: missing lifetime specifier
--> src\main.rs:3:58
|
3 | fn parse_type(p: &mut Parser) -> Result<&str, cssparser::BasicParseError> {
| ----------- ^^^^^^^^^^^^^^^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say which one of `p`'s 3 lifetimes it is borrowed from
help: consider introducing a named lifetime parameter
|
3 | fn parse_type<'a>(p: &'a mut Parser) -> Result<&str, cssparser::BasicParseError<'a>> {
| ^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
The compiler will try to deduce lifetimes automatically as best it can, but p has three lifetimes &'1 Parser<'2, '3> involved, so it doesn't know what lifetime &'_ str or BasicParseError<'_> should be deduced to.
Looking at the signature for Parser::expect_function_matching, you probably want:
fn parse_type<'i>(p: &mut Parser<'i, '_>) -> Result<&'i str, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
}
Of course, while everything #kmdreko has said is absolutely correct, replacing your closure with a function will only work if you're not capturing any environment—and if that's the case, you could simply declare that parse_type is a function pointer with the relevant type and Rust will coerce the closure accordingly:
let parse_type: for<'i> fn(&mut Parser<'i, '_>) -> Result<_, cssparser::BasicParseError<'i>> = |p| {
p.expect_function_matching("type")?;
Ok("OK")
};
If however your closure does capture environment, then I guess the extension of #kmdreko's approach would be to define a struct to hold that environment and then have some implementation on that struct that defines an appropriate method. But that's a lot of grunt. You could instead make parse_type a trait object for one of the Fn traits and use an analog of the above approach:
let parse_type: &dyn for<'i> Fn(&mut Parser<'i, '_>) -> Result<_, cssparser::BasicParseError<'i>> = &|p| {
p.expect_function_matching("type")?;
Ok("OK")
};
In theory this will add an additional layer of indirection when invoking the closure, but I think in practice the optimiser will remove it (unless you pass the closure between functions, at least). And it'd be a pretty irrelevant expense in most cases anyway.
Finally, if your input_string actually comes from a function argument, then you'll be able to name its lifetime in the function signature and use that directly in your closure definition:
fn example<'i>(input_string: &'i str) {
let mut parser_input = ParserInput::new(input_string);
let mut parser = Parser::new(&mut parser_input);
let parse_type = |p: &mut Parser<'i, '_>| -> Result<_, cssparser::BasicParseError<'i>> {
p.expect_function_matching("type")?;
Ok("OK")
};
let res = parse_type(&mut parser);
}

Why can I not return a reference from a closure?

fn main() {
let _ref_in_ref_out = |var: &i64| var;
}
This does not compile:
error: lifetime may not live long enough
--> src/main.rs:2:39
|
2 | let _ref_in_ref_out = |var: &i64| var;
| - - ^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 i64
| let's call the lifetime of this reference `'1`
Apparently the compiler infers two different lifetimes (for the argument and the return type), instead of it being the same.
Is it possible to write a closure so that the input lifetime is the same as the output lifetime?
Something like
fn ref_in_ref_out<'a> (var: &'a i64) -> &'a i64 { var }
but as a closure
Lifetime elisions rules do not apply to closures, neither can you explicitly specify lifetimes for closures. There are several ways to make this code work, though.
The easiest solution is to simply omit the type annotations and let the compiler infer everything:
let ref_in_ref_out = |var| var;
let i: i64 = 42;
ref_in_ref_out(&i);
Alternatively, it's actually fine to specify the return type. This compiles:
let _ref_in_ref_out = |var| -> &i64 { var };
Yet another option for the case that your closure does not close over any local variables is to convert it to a function pointer, since lifetime elision rules apply to function pointers:
let ref_in_ref_out: fn(&i64) -> &i64 = |var| var;
And finally the most general solution is to use a helper function to apply a function trait bound to your closure:
fn constrain_closure<F: Fn(&i64) -> &i64>(f: F) -> F {
f
}
let _ref_in_ref_out = constrain_closure(|var| var);
I've just found out a way to solve this issue, but It'd be great if there is an easier solution:
fn infer_lifetime<'a, T: 'a, F: Fn(&'a T) -> &'a T>(f: F) -> F {
f
}
fn main() {
let _ref_in_ref_out = infer_lifetime(|var: &i64| var);
}

How can I return an impl Iterator that has multiple lifetimes?

I'm having trouble with lifetimes on an impl trait. I'm trying to get the following code to work:
struct Foo<'op, Input> {
op: Box<dyn Fn(Input) -> i32 + 'op>,
}
impl<'op, Input> Foo<'op, Input> {
fn new<Op>(op: Op) -> Foo<'op, Input>
where
Op: Fn(Input) -> i32 + 'op,
{
Foo { op: Box::new(op) }
}
fn apply<'input_iter, InputIter>(
self,
input_iter: InputIter,
) -> impl Iterator<Item = i32> + 'op + 'input_iter
where
InputIter: IntoIterator<Item = Input> + 'input_iter,
{
input_iter.into_iter().map(move |input| (self.op)(input))
}
}
(Playground)
This is giving me the following error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:20:36
|
20 | input_iter.into_iter().map(move |input| (self.op)(input))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'op as defined on the impl at 5:6...
--> src/lib.rs:5:6
|
5 | impl<'op, Input> Foo<'op, Input> {
| ^^^
= note: ...so that the types are compatible:
expected Foo<'_, _>
found Foo<'op, _>
note: but, the lifetime must be valid for the lifetime 'input_iter as defined on the method body at 13:14...
--> src/lib.rs:13:14
|
13 | fn apply<'input_iter, InputIter>(
| ^^^^^^^^^^^
note: ...so that return value is valid for the call
--> src/lib.rs:16:10
|
16 | ) -> impl Iterator<Item = i32> + 'op + 'input_iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here's my understanding of the lifetimes involved. Foo owns an op, which is a closure that may have a reference in it somewhere, so it may have a bound lifetime. This is denoted by 'op, and Foo is constrained such that it can't outlive it. So far, so good.
In apply(), the idea is that we want to consume an input_iter and self and return an iterator of each element in input_iter mapped using self.op. input_iterator may also contain references, so it may have its own lifetime bounds, denoted by 'input_iter.
What I want is to return an iterator that takes ownership of both self and input_iter. In doing so, it would have to take on both of their lifetime parameters to ensure that it didn't outlast either the input_iter references or the op references. I thought impl Iterator<Item = i32> + 'op + 'input_iter would accomplish this, but I seem to have taken a wrong turn somewhere.
It's also weird that it's complaining about the closure. I understand that the closure can't outlive 'op, because it takes ownership of the operator and its references. That makes perfect sense. What I don't understand is why it needs to live as long as 'input_iter. The closure and the input iterator shouldn't care about each other at all; the only thing connecting them is that they both have the same owner (the output iterator).
What am I missing here?
Lifetime parameters don't always represent the exact lifetime of an object (or of a borrow). Let's consider this example:
fn main() {
let a = 3;
let b = 5;
let c = min(&a, &b);
println!("{:?}", c);
}
fn min<'a>(a: &'a i32, b: &'a i32) -> &'a i32 {
if a < b {
a
} else {
b
}
}
Here, min takes two reference arguments with the same lifetime. However, we call it with borrows of different variables, which have different lifetimes. So why does this code compile?
The answer is subtyping and variance. Larger lifetimes are subtypes of shorter lifetimes; conversely, shorter lifetimes are supertypes of larger lifetimes. In the example above, the compiler has to find one lifetime that is compatible with both input lifetimes. The compiler does this by finding the common supertype of both lifetimes (i.e. the shortest lifetime that contains both). This is called unification.
Back to your problem. It seems like the compiler doesn't handle multiple lifetime bounds on impl Trait too well at the moment. However, there's no real need to have two lifetime bounds: one is enough. The compiler will shorten this single lifetime if necessary to satisfy the requirements of both self and input_iter.
struct Foo<'op, Input> {
op: Box<dyn Fn(Input) -> i32 + 'op>,
}
impl<'op, Input> Foo<'op, Input> {
fn new<Op>(op: Op) -> Foo<'op, Input>
where
Op: Fn(Input) -> i32 + 'op,
{
Foo { op: Box::new(op) }
}
fn apply<InputIter>(
self,
input_iter: InputIter,
) -> impl Iterator<Item = i32> + 'op
where
Input: 'op,
InputIter: IntoIterator<Item = Input> + 'op,
{
input_iter.into_iter().map(move |input| (self.op)(input))
}
}
fn main() {
let y = 1;
let foo = Foo::new(|x| x as i32 + y);
let s = "abc".to_string();
let sr: &str = &*s;
let bar = sr.chars();
let baz: Vec<_> = foo.apply(bar).collect();
println!("{:?}", baz);
}
Try moving the lines in main around to convince yourself that the lifetimes are indeed unified.
At this point, calling the lifetime 'op is somewhat misleading; it might as well be called 'a.

Pass a Struct<'a>::method as a `for<'a> Fn(&Foo<'a>)` for use in a closure

In my tests I had a helper function that runs a given method on differently configured objects, with a simplified version looking like this:
fn run_method<F>(f: F)
where
F: Fn(&Foo),
{
let to_test = vec![0i32];
to_test
.iter()
.map(|param| {
let foo = Foo(*param);
f(&foo);
})
.for_each(drop);
}
// run_method(Foo::run);
This worked fine until I added references to the tested struct, making it "lifetime-annotated" (for lack of a proper term, I mean Foo<'a>).
Now I get an error indicating, I think, that Rust doesn't want to accept a Foo::method as a function that can be used with any given lifetime (i.e. F: for<'a> Fn(&Foo<'a>)), as required by the closure:
error[E0631]: type mismatch in function arguments
--> src/main.rs:54:5
|
3 | fn run(&self) {
| ------------- found signature of `for<'r> fn(&'r Foo<'_>) -> _`
...
54 | run_method(Foo::run);
| ^^^^^^^^^^ expected signature of `for<'r, 's> fn(&'r Foo<'s>) -> _`
|
note: required by `run_method`
--> src/main.rs:44:1
|
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `for<'r, 's> <for<'t0> fn(&'t0 Foo<'_>) {Foo::<'_>::run} as std::ops::FnOnce<(&'r Foo<'s>,)>>::Output == ()`
--> src/main.rs:54:5
|
54 | run_method(Foo::run);
| ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `run_method`
--> src/main.rs:44:1
|
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I can work around the problem by avoiding closures (though I don't really understand how 'a gets constrained to be local to run_method - isn't the lifetime parameter supposed to be chosen by the caller?):
fn run_method<'a, F>(f: F)
where
F: Fn(&Foo<'a>),
{
let to_test = vec![&0i32];
for param in to_test {
let foo = Foo(param);
f(&foo);
}
}
Can I fix this without rewriting? If not - is there a reason why this shouldn't work?
Complete code:
struct Foo<'a>(&'a i32);
impl<'a> Foo<'a> {
fn run(&self) {
println!("Hello {}", self.0);
}
}
fn run_method<F>(f: F)
where
F: Fn(&Foo),
{
//same as F: for<'a> Fn(&Foo<'a>) {
let to_test = vec![0i32];
to_test
.iter()
.map(|param| {
let foo = Foo(param);
f(&foo);
})
.for_each(drop);
}
fn main() {
run_method(Foo::run);
}
// This works:
// fn run_method<'a, F>(f: F)
// where
// F: Fn(&Foo<'a>),
// {
// let to_test = vec![&0i32];
// for param in to_test {
// let foo = Foo(param);
// f(&foo);
// }
// }
// The lifetime-less version:
// struct Foo(i32);
// impl Foo {
// fn run(&self) {
// println!("Hello {}", self.0);
// }
// }
//
// fn run_parser_method<F>(f: F)
// where
// F: Fn(&Foo),
// {
// let to_test = vec![0i32];
// to_test
// .iter()
// .map(|param| {
// let foo = Foo(*param);
// f(&foo);
// })
// .for_each(drop);
// }
//
// fn main() {
// run_parser_method(Foo::run);
// }
playground
An overview of other questions about the same error code:
Expected bound lifetime parameter, found concrete lifetime is about mismatch between trait definition and implementation (trait { fn handle<'a>(); } vs impl<'a> { fn handle() {} })
Function references: expected bound lifetime parameter , found concrete lifetime [E0271] as well as Expected bound lifetime parameter, found concrete lifetime [E0271] is about a closure |args| {...} without explicit type annotations (|args: &[&str]|) not being accepted as a Fn(&[&str]) -> (); the answers don't explain why (the latter hints that it was not implemented in 2015)
Type mismatch "bound lifetime parameter" vs "concrete lifetime" when filling a collection from a closure is again about a closure without explicit type annotations specifying that it accepts a reference (let mut insert = |k| seq.insert(k); (1..10).cycle().take_while(insert)), which masks a more useful "borrowed data cannot be stored outside of its closure" error.
I can work around the problem by avoiding closures (though I don't really understand how 'a gets constrained to be local to run_method - isn't the lifetime parameter supposed to be chosen by the caller?)
It is. But when you rewrite it without closures, you have also put the reference inside the vec! invocation, so it is no longer constructed at runtime. Instead, the compiler can infer that to_test has type Vec<&'static i32>, and as 'static outlives any caller-chosen lifetime, there's no violation.
This fails to compile as you expect:
let to_test = vec![0i32];
for param in to_test.iter() {
let foo = Foo(param);
f(&foo);
}
is there a reason why this shouldn't work?
Yes, because the type of run is constrained by the type of Foo. More specifically, you have a lifetime decided by the caller (implicitly, in the type for Foo), so you have to construct a Foo of that lifetime to invoke the given run reference on it.
Can I fix this without rewriting?
That depends.
If all your test values are literals, you can make 'static references.
If you're able and willing to rewrite run, it's possible to make it unconstrained by the type of Foo
impl<'a> Foo<'a> {
fn run<'s>(_self: &Foo<'s>) {
println!("Hello {}", _self.0);
}
}
But then it doesn't need to go in an impl block at all.
I think the solution provided in the comments is your best bet, because given that you don't care about your concrete Foo<'a> type, there's no need to give the method reference for that type.

Resources