Generic for FnOnce that returns a future with a lifetime - rust

I have a struct that needs a callback that returns a future whose output has a lifetime:
struct Foo;
struct Bar;
struct Baz<F>
where F: for<'a> FnOnce(&'a Foo) -> impl std::future::Future<Output=&'a Bar> // ?
{
cb: F
}
That doesn't compile, with a syntax error since impl can't appear in trait bounds:
Compiling playground v0.0.1 (/playground)
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/lib.rs:6:37
|
6 | where F: for<'a> FnOnce(&'a Foo) -> impl std::future::Future<Output=&'a Bar>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
This doesn't compile either:
struct Foo;
struct Bar;
struct Baz<O, F>
where
O: for<'a> std::future::Future<Output=&'a Bar>,
F: for<'b> FnOnce(&'b Foo) -> O,
{
cb: F
}
Complaining that 'a isn't recognized (and the lifetimes 'a and 'b would be unrelated):
Compiling playground v0.0.1 (/playground)
error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
--> src/lib.rs:7:36
|
7 | O: for<'a> std::future::Future<Output=&'a Bar>,
| ^^^^^^^^^^^^^^
error: aborting due to previous error
Is there a way to specify this relationship?

It's a bit ugly, but this is the best way I could find (using struct Foo(Bar) for demonstration):
Playground
use std::future::Future;
struct Bar;
struct Foo(Bar);
trait FooClosure<'a> {
type Fut: Future<Output = &'a Bar>;
fn call(self, foo: &'a Foo) -> Self::Fut;
}
impl<'a, Fut: Future<Output = &'a Bar>, C: FnOnce(&'a Foo) -> Fut> FooClosure<'a> for C {
type Fut = Fut;
fn call(self, foo: &'a Foo) -> Fut {
self(foo)
}
}
struct Baz<F: for<'a> FooClosure<'a>>(F);
fn main() {
let closure: Box<dyn for<'a> FnOnce(&'a Foo) -> futures::future::Ready<&'a Bar>> =
Box::new(|foo| futures::future::ready(&foo.0));
let baz = Baz(closure);
}
I couldn't get the compiler to infer the types properly, so I had to wrap the closure as boxed trait object. Theoretically this shouldn't be necessary, and there might be a way to avoid this but I couldn't figure it out.
Note: I think there are plans to make your original code work without needing this trait black magic.

A straightforward way to do this is to parameterize the struct Baz itself with the lifetime parameter:
struct Baz<'a, O: Future<Output=&'a Bar>, F: FnOnce(&'a Foo) -> O> {
cb: F,
phantom: PhantomData<&'a O>,
}
The PhantomData instance is required to "use" the lifetime parameter 'a and the output type parameter O. You can think of O and 'a as components of the closure type F -- they will always be implicitly inferred from the lifetime and return type used by F.
Playground

Related

Borrow checker issue trying to pass a function pointer as paramerter

I am seeking help to understand why the borrow checker fails for the following minimal non-working example, and I would be very happy to learn how to correctly implement what I was trying to do:
use std::collections::HashSet;
struct Foo {
data: HashSet<usize>
}
impl Foo {
fn test<'a, F, T>(&mut self, _operation: F) -> ()
where F: Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
T: Iterator<Item=&'a usize>
{
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation(&self.data, &update).copied().collect();
}
fn new() -> Self {
Foo { data: HashSet::new() }
}
}
fn main() {
let mut foo: Foo = Foo::new();
foo.test(HashSet::intersection);
}
My main source of confusion is that, if I replace the call to _operation with HashSet::intersection, the code compiles. I thought that the type of the parameter _operation would allow me to pass both HashSet::intersection and HashSet::union as operations here.
For the record, this is the error I receive:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src\main.rs:13:32
|
13 | self.data = _operation(&self.data, &update).copied().collect();
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 8:23...
--> src\main.rs:8:23
|
8 | fn test<'a, F, T>(&mut self, _operation: F) -> ()
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:13:32
|
13 | self.data = _operation(&self.data, &update).copied().collect();
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the method body at 8:13...
--> src\main.rs:8:13
|
8 | fn test<'a, F, T>(&mut self, _operation: F) -> ()
| ^^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:13:32
|
13 | self.data = _operation(&self.data, &update).copied().collect();
| ^^^^^^^^^^
For more information about this error, try `rustc --explain E0495`.
error: could not compile `aoc06` due to previous error
The issue, as the (albeit cryptic) compiler message suggests, is that there is a lifetime mismatch: _operation expects HashSet references that live as long as 'a, but &self.data has a lifetime 'b, the elided lifetime of &mut self, and &update has a different lifetime that lasts the duration of the test function body.
To resolve this issue, we must specify that the function type F takes in HashMap references of arbitrary lifetimes, not just the specific lifetime 'a -- this lets the compiler infer the appropriate lifetime when _operation is invoked. This is why we need Higher-Rank Trait Bounds (HRTBs):
fn test<F, T>(&mut self, _operation: F) -> ()
where F: for<'a> Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
However, this raises another issue. How do we apply the higher-ranked lifetime 'a to the type parameter T? Unfortunately Rust does not support higher-kinded types, but we can get away with "abstracting" out the the function type F and the higher-kinded type T to a trait and an associated type on said trait.
trait Operation<'a, T: 'a> {
type Output: Iterator<Item = &'a T>;
fn operate(self, a: &'a HashSet<T>, b: &'a HashSet<T>) -> Self::Output;
}
The Operation trait represents an operation on two HashSets that returns an iterator over references, equivalent to the functions HashSet::union, HashSet::intersection, and the like. We can achieve this using the following impl, which ensures that HashSet::intersection and the like implement Operation:
impl<'a, T: 'a, I, F> Operation<'a, T> for F
where
I: Iterator<Item = &'a T>,
F: FnOnce(&'a HashSet<T>, &'a HashSet<T>) -> I,
{
type Output = I;
fn operate(self, a: &'a HashSet<T>, b: &'a HashSet<T>) -> Self::Output {
self(a, b)
}
}
We can then use a HRTB on the Operation trait instead, which does not require any nested higher-kinded types:
fn test(&mut self, _operation: impl for<'a> Operation<'a, usize>) -> () {
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation.operate(&self.data, &update).copied().collect();
println!("{:?}", self.data);
}
Playground
The arguments you are passing do not match the lifetime which you declared the Fn bound with.
fn test<'a, F, T>(&mut self, _operation: F) -> ()
'a is some arbitrary lifetime that may be specified by the caller,
F: Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
which must be adequate for the references given to _operation,
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation(&self.data, &update).copied().collect();
but here you pass in a borrow from self (whose lifetime is not specified to outlive 'a) and a borrow from update (which is a local variable, which cannot outlive 'a).
In order to correctly write this, you need to specify that _operation may be called with any lifetime (which thus includes the lifetimes of borrows of local variables). That's simple, by itself:
fn test<F, T>(&mut self, _operation: F) -> ()
where
F: for<'a> Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
Note that 'a is no longer a lifetime parameter of test. Instead it's part of the bound on F: you can read this for<'a> notation as “for any lifetime, which we will call 'a, F may be called as a function with references &'a ...”.
However, this isn't actually a solution, because you also have T: Iterator<Item = &'a usize>, which uses 'a again. It isn't currently possible to write a where clause that expresses this relationship, particularly as even without the item being a reference, the iterator will be borrowing the &'a HashSets.
This is an unfortunate limitation of current Rust — it also comes up in trying to write a function that takes an async function which borrows an input (which is structurally the same as your situation, with Future in place of Iterator). However, there is a workaround: you can define a trait for the function, which has a single lifetime parameter that links everything together. (This doesn't impose any extra work on the caller of your function, because the trait is blanket implemented for all suitable functions.)
Here's your code with such a trait added and the needed modifications to fn test():
use std::collections::HashSet;
trait IteratorCallback<'a> {
type Output: Iterator<Item = &'a usize> + 'a;
fn call(self, a: &'a HashSet<usize>, b: &'a HashSet<usize>) -> Self::Output;
}
impl<'a, F, T> IteratorCallback<'a> for F
where
F: FnOnce(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
T: Iterator<Item = &'a usize> + 'a,
{
type Output = T;
fn call(self, a: &'a HashSet<usize>, b: &'a HashSet<usize>) -> T {
// Delegate to FnOnce
self(a, b)
}
}
struct Foo {
data: HashSet<usize>,
}
impl Foo {
fn test<F>(&mut self, _operation: F) -> ()
where
F: for<'a> IteratorCallback<'a>,
{
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation.call(&self.data, &update).copied().collect();
}
fn new() -> Self {
Foo {
data: HashSet::new(),
}
}
}
fn main() {
let mut foo: Foo = Foo::new();
foo.test(HashSet::intersection);
}
Note: I changed the function bound to FnOnce because that's more permissive than Fn and all you need in this case, but the same technique will work with Fn as long as you change fn call(self, to fn call(&self,.
Credit: I used this Reddit comment by user Lej77 as an example to work from for the trait technique.

lifetime of function pointer is for<'a, '_> while it should be for<'r>

Sometimes I struggle with lifetimes. I'm still learning and I don't know what's happening here:
use std::future::Future;
use futures::future::{BoxFuture, FutureExt};
struct M{}
struct Client{}
impl Client {
async fn send_and_expect<'a>(
&'a mut self,
m: &M
) -> std::result::Result<(), ()> {
Ok(())
}
pub fn connection_retrier<'a, T>(
f: fn(&'a mut Self, &M) -> T,
f_self: &'a mut Self,
f_m: &'a M,
)-> BoxFuture<'a, std::result::Result<(),()>>
where
T: Future<Output = std::result::Result<(), ()>> + 'a
{
async move {
Client::send_and_expect(f_self, f_m).await
}.boxed()
}
async fn send_with_retry<'a>(&'a mut self) -> std::result::Result<(), ()> {
let m = M{};
Client::connection_retrier(
Client::send_and_expect,
&mut *self, &m).await
}
}
Error:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:31:21
|
11 | ) -> std::result::Result<(), ()> {
| --------------------------- the `Output` of this `async fn`'s found opaque type
...
31 | Client::send_and_expect,
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&mut Client, &'r M) -> impl futures::Future`
found fn pointer `for<'a, '_> fn(&'a mut Client, &M) -> impl futures::Future
Playground
I'm now completely confused about why in for<'r> fn(&mut Client, &'r M) -> impl futures::Future, &mut Client has no lifetime. And what does _ means in for<'a, '_> fn(&'a mut Client, &M) -> impl futures::Future`?
I'm very intersted in learning what's happening here.
Cleaning up the code
In order to see this code from the compiler's perspective, let's change all the lifetime parameters in this example to be explicit and have distinct names, expand the async fn sugar, and then look at how the error changes.
The above example is equivalent to the following after lifetime inference and desugaring.
// name the second lifetime, and expand the async fn sugar.
fn send_and_expect<'a, 'b>(&'a mut self, m: &'b M) -> impl Future<Item=Result<(), ()>> + 'a + 'b
{ ... }
// rename 'a to 'c to avoid ambiguous lifetime names
pub fn connection_retrier<'c, T>(
f: for<'d> fn(&'c mut Self, &'d M) -> T, // name the implicit higher-ranked lifetime here
f_self: &'c mut Self,
f_m: &'c M,
)-> BoxFuture<'c, std::result::Result<(), ()>>
where T: Future<Output = std::result::Result<(), ()>> + 'c
{ ... }
// rename 'a to 'e to avoid ambiguous lifetime names
async fn send_with_retry<'e>(&'e mut self) -> std::result::Result<(), ()> {
After making this change, the error becomes:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:31:21
|
11 | ) -> std::result::Result<(), ()> {
| --------------------------- the `Output` of this `async fn`'s found opaque type
...
31 | Client::send_and_expect,
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'d> fn(&mut Client, &'d M) -> impl futures::Future`
found fn pointer `for<'a, 'b> fn(&'a mut Client, &'b M) -> impl futures::Future`
This should clarify your question about '_: it's just the name the compiler gave the inferred second lifetime parameter of send_and_expect. As for the missing lifetime on &mut Client, you can see that it's still missing here. For reasons I do not completely understand, and in ways that depend on the exact error message given, the compiler will sometimes omit concrete lifetimes when printing the type of references, but make no mistake, the lifetime of that reference is 'c.
Solving the error
Onto the actual problem. The signature of f indicates that connection_retrier is expecting a function which (1) takes a reference of lifetime &'c and (2) a reference of any other lifetime, and (3) returns a Future type which will remain valid as long as 'c does, as specified by your where bound.
When we pass send_and_expect to connection_retrier, in order for the signatures to match the compiler is coercing it to the type for<'d> send_and_expect::<'c, 'd>. But that type doesn't meet condition (3) above! Unlike a regular function, the default behavior of an async function is to capture all input lifetimes in its return type, so the return type of for<'d> send_and_expect::<'c, 'd> is in fact impl Future<Item=Result<(), ()>> + 'c + 'd, as you can tell by looking at send_and_expect's expanded signature.
Since this type borrows from the two lifetimes 'c and 'd, and there is no constraint that 'd: 'c (read: 'd outlives 'c), it may not remain valid for the entirety of the lifetime 'c, if 'd ends first. It is this mismatch that results in the rather cryptic lifetime error you received. There are two ways you can solve this problem, depending on your preferred semantics. You can either:
Remove the higher-ranked bound from f entirely, and specify exactly the lifetimes you will be calling it with in connection_retrier (both &'c.)
pub fn connection_retrier<'c, T>(
f: fn(&'c mut Self, &'c M) -> T
f_self: &'c mut Self,
f_m: &'c M,
) -> BoxFuture<'c, std::result::Result<(), ()>>
where T: Future<Output = std::result::Result<(), ()>> + 'c
{ ... }
Keep the signature of connection_retrier the same and specify that the future returned by send_and_expect only borrows from its first argument. To do this, you will need to drop the async fn sugar on the signature and wrap the body in an async move block.
fn send_and_expect<'a, 'b>(&'a mut self, m: &'b M) -> impl Future<Output=Result<(), ()>> + 'a
{ async move { ... } }
Note that you cannot solve this by writing the type of f as for<'d: 'c> fn(&'c mut Self, &'d M) -> T, as bounds are currently not permitted for universally quantified lifetimes.

Why Rust complains about lifetime of types in functions that don't use instances of these types?

Rust requires lifetimes for types that don't have instances:
use futures::future::BoxFuture;
struct A{
}
impl A{
async fn send_and_expect<T>(&mut self, unauthorized_retry: i32) -> std::result::Result<(),()>{
Err(())
}
fn send_and_expect_wrapper<'a, T>(&'a mut self, unauthorized_retry: i32)
-> BoxFuture<'a, std::result::Result<(),()>> {
Box::pin(self.send_and_expect::<T>(unauthorized_retry))
}
}
Error:
Standard Error
Compiling playground v0.0.1 (/playground)
error[E0309]: the parameter type `T` may not live long enough
--> src/lib.rs:15:9
|
13 | fn send_and_expect_wrapper<'a, T>(&'a mut self, unauthorized_retry: i32)
| - help: consider adding an explicit lifetime bound...: `T: 'a`
14 | -> BoxFuture<'a, std::result::Result<(),()>> {
15 | Box::pin(self.send_and_expect::<T>(unauthorized_retry))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `impl futures::Future` will meet its required lifetime bounds
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
I have to do fn send_and_expect_wrapper<'a, T>(&'a mut self, unauthorized_retry: i32)
Is there a reason? I never use an instance of T so there are no concerns about lifetime.
The type check does checking on types. From its point of view, a value only does propagating it's type and triggering actions on the type (such as coercing). And in your example T is involved into unsized coercion with : 'a bound. Why? See how BoxFuture is declared
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a, Global>>;
Desugared and extremely minimized example would be like:
pub trait Future {}
struct Closure<'a, T> {
receiver: &'a mut (),
params: std::marker::PhantomData<T>,
}
impl<'a, T> Future for Closure<'a, T> {}
fn foo<'a, T>() {
let x: *mut Closure<'a, T>;
let coerced: *mut (dyn Future + 'a) = x;
}
This gives the same error[E0309].
The point is in a type checking rule: U = dyn _ + 'a implies U: 'a. Or simply (dyn _ + 'a): 'a
Applying this to our example (U = Closure<'a, T>) we get Closure<'a, T>: 'a which implies the same bound should hold on the substitutions, i.e. 'a: 'a and T: 'a. But our environment (the foo fn signature) tells nothing about the T: 'a requirement, hence the error.

Implementing a trait for closures results in bound/concrete lifetime mismatch

I want to implement a trait for closures of a specific type. Here is a minimal example (playground):
trait Foo {
fn foo(&self, x: &u32);
}
impl<F> Foo for F
where F: Fn(&u32)
{
fn foo(&self, x: &u32) {
self(x)
}
}
fn main() {
let _: &FnOnce(&u32) = &|x| {}; // works
let _: &Foo = &|x| {}; // doesn't work
}
It results in this error:
error: type mismatch resolving `for<'r> <[closure#<anon>:16:29: 16:35] as std::ops::FnOnce<(&'r u32,)>>::Output == ()`:
expected bound lifetime parameter ,
found concrete lifetime [--explain E0271]
--> <anon>:16:28
|>
16 |> let _: &Foo = &|x| {};
|> ^^^^^^^
note: required because of the requirements on the impl of `Foo` for `[closure#<anon>:16:29: 16:35]`
note: required for the cast to the object type `Foo`
error: type mismatch: the type `[closure#<anon>:16:29: 16:35]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r u32,)>` is required (expected concrete lifetime, found bound lifetime parameter ) [--explain E0281]
--> <anon>:16:28
|>
16 |> let _: &Foo = &|x| {};
|> ^^^^^^^
note: required because of the requirements on the impl of `Foo` for `[closure#<anon>:16:29: 16:35]`
note: required for the cast to the object type `Foo`
I already tried to explicitly add the HRTB to the where clause like this:
where F: for<'a> Fn(&'a u32)
But it didn't help. I also declared the lifetime on the impl block instead, like this:
impl<'a, F> Foo for F
where F: Fn(&'a u32) { ... }
But this results in a lifetime error within the impl block. I think that those errors are right and the lifetime parameter can't be declared on the impl block.
How can I fix this example?
Check out this part of the error:
[...] implements the trait std::ops::Fn<(_,)>, but the trait for<'r> std::ops::Fn<(&'r u32,)> is required
I think that basically there's not enough code to allow types to be properly inferred. Adding an explicit type annotation allows the example to be compiled:
let _: &Foo = &|x: &u32| {};
Here's a partial answer, starting with an interesting experiment:
trait Foo {
fn foo(&self, x: &u32);
}
impl<F> Foo for F
where F: Fn(&u32)
{
fn foo(&self, x: &u32) {
self(x)
}
}
fn main() {
let f1: &Fn(&u32) = &|_x| {};
let f2: &Foo = &f1;
// but this fails:
// let f3: &Foo = &|_x| {};
f2.foo(&3);
}
(Playground)
All I've done is change the FnOnce to Fn for consistency with the trait, and assign your first closure to a binding of type &Foo - and this one work.
This tells me that the trait itself is fine - it's a problem inferring the type of the closure when making the trait object. Going back to the error, we're told that the closure implements std::ops::Fn<(_,)>, but for<'r> std::ops::Fn<(&'r u32,)> is required. This means that the first thing you tried (adding the for<'r>... to the trait) didn't have any effect because the trait already requires this.
At this point I'm stuck - I don't think I understand the inference rules for closures in enough detail to see either why there's a difference, or how to make it work. I'm hoping someone will come and fill that in!
Disclaimer: I have no idea what I'm doing.
The following works:
trait Foo<'a> {
fn foo(&self, x: &'a u32);
}
impl<'a, F> Foo<'a> for F where F: Fn(&'a u32) {
fn foo(&self, x: &'a u32) {
self(x)
}
}

How do you write a trait that returns an iterator?

Broadly speaking my goal is this:
For some known type Bar...
Have a trait Foo with a function: get_iterator<T>() -> T where T: Iterator<Item = Bar>
The instance of the iterator borrows the original object Foo is implemented on.
I imagine it working like this:
let mut foo = Foo;
let bar = foo.get_iterator();
foo.mutable_call(); // <-- This fails, because foo is borrowed in bar
for x in bar {
...
}
So, that's the goal, and here's my attempt, which I can't seem to get working:
struct ValsFromT<'a, T: 'a> {
parent:&'a T,
offset: usize,
}
struct Val;
trait HasValsIterator<T> {
fn val_iterator(&self) -> T where T: Iterator<Item = Val>;
}
struct Foo;
impl<'a> Iterator for ValsFromT<'a, Foo> {
type Item = Val;
fn next(&mut self) -> Option<Val> {
return None;
}
}
impl<'a> HasValsIterator<ValsFromT<'a, Foo>> for Foo {
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
return ValsFromT {
offset: 0usize,
parent: self
};
}
}
fn takes_vals<T>(instance:T) where T: HasValsIterator<T> {
// ...
}
#[test]
fn test_foo() {
let x = Foo;
takes_vals(x);
}
(playpen: http://is.gd/wys3fx)
We're getting the dreaded concrete/bound lifetime error here, because of trying to return an iterator instance that references self from the trait function:
<anon>:22:3: 27:4 error: method `val_iterator` has an incompatible type for trait:
expected bound lifetime parameter ,
found concrete lifetime [E0053]
<anon>:22 fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
<anon>:23 return ValsFromT {
<anon>:24 offset: 0usize,
<anon>:25 parent: self
<anon>:26 };
<anon>:27 }
<anon>:22:3: 27:4 help: see the detailed explanation for E0053
Is there some way of doing this?
Unfortunately, Veedrac's suggestion doesn't work directly. You will get the following error if you'd try to use val_iterator() method on instance inside takes_vals():
<anon>:31:25: 31:39 error: the trait `core::iter::Iterator` is not implemented for the type `U` [E0277]
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~~~~~~~
<anon>:31:25: 31:39 help: see the detailed explanation for E0277
<anon>:31:25: 31:39 note: `U` is not an iterator; maybe try calling `.iter()` or a similar method
error: aborting due to previous error
playpen: application terminated with error code 101
This (and some other further errors) requires changing the signature of the function to this one:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U>
However, even this doesn't work yet:
<anon>:31:16: 31:24 error: `instance` does not live long enough
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~
<anon>:30:97: 32:2 note: reference must be valid for the lifetime 'a as defined on the block at 30:96...
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
<anon>:30:97: 32:2 note: ...but borrowed value is only valid for the scope of parameters for function at 30:96
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
Remember that the trait requires that val_iterator() accepts the target by reference with lifetime 'a. This lifetime in this function is an input parameter. However, when val_iterator() is called on instance, the only lifetime which can be specified for the reference is the one of instance which is strictly smaller than any possible 'a as a parameter, because it is a local variable. Therefore, it is not possible to pass instance by value; you can only pass it by reference for lifetimes to match:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: &'a T) where T: HasValsIterator<'a, U> {
let iter = instance.val_iterator();
}
This works.
I'd like to add that using associated types instead of type parameters would be more correct semantically:
trait HasValsIterator<'a> {
type Iter: Iterator<Item=Val> + 'a;
fn val_iterator(&'a self) -> Self::Iter;
}
impl<'a> HasValsIterator<'a> for Foo {
type Iter = ValsFromT<'a, Foo>;
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> { ... }
}
fn takes_vals<'a, T: 'a>(instance: &'a T) where T: HasValsIterator<'a> {
...
}
I say that this is more correct because the type of the iterator is determined by the implementor, that is, it is "output" type, which are modeled by associated types. As you can see, takes_vals() signature also shrank considerably.
Ideally, HasValsIterator trait should have been defined like this:
trait HasValsIterator {
type Iter<'a>: Iterator<Item=Val> + 'a
fn val_iterator<'a>(&'a self) -> Iter<'a>;
}
This way, val_iterator() would in any situation, including when HasValsIterator implementor is passed by value. However, Rust is not there yet.

Resources