Why do the lifetimes on a trait object passed as an argument require Higher Ranked Trait Bounds but a struct doesn't? - rust

How are lifetimes handled when there is a trait object passed to a function?
struct Planet<T> {
i: T,
}
trait Spinner<T> {
fn spin(&self, value: T);
}
impl<T> Spinner<T> for Planet<T> {
fn spin(&self, value: T) {}
}
// foo2 fails: Due to lifetime of local variable being less than 'a
fn foo2<'a>(t: &'a Spinner<&'a i32>) {
let x: i32 = 10;
t.spin(&x);
}
// foo1 passes: But here also the lifetime of local variable is less than 'a?
fn foo1<'a>(t: &'a Planet<&'a i32>) {
let x: i32 = 10;
t.spin(&x);
}
(Playground)
This code results in this error:
error[E0597]: `x` does not live long enough
--> src/main.rs:16:17
|
16 | t.spin(&x);
| ^ borrowed value does not live long enough
17 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:5...
--> src/main.rs:14:5
|
14 | fn foo2<'a>(t: &'a Spinner<&'a i32>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The function signature of foo1 is nearly same as foo2. One receiving the reference to struct and the other a trait object.
I read this is where Higher Ranked Trait Bounds comes in. Modifying foo2 as foo2(t: &for<'a> Spinner<&'a i32>) compiles the code, but I don't understand why.
Why won't 'a shrink for x?
Citing the Nomicon:
How on earth are we supposed to express the lifetimes on F's trait bound? We need to provide some lifetime there, but the lifetime we care about can't be named until we enter the body of call! Also, that isn't some fixed lifetime; call works with any lifetime &self happens to have at that point.
Can this please be elaborated?

In short: foo1 compiles because most types are variant over their generic parameters and the compiler can still chose a Spinner impl for t. foo2 doesn't compile because traits are invariant over their generic parameters and the Spinner impl is already fixed.
Some explanation
Let's take a look at a third version of foo:
fn foo3<'a>(t: &'a Planet<&'a i32>) {
let x: i32 = 10;
Spinner::<&'a i32>::spin(t, &x);
}
This results in the same error as your foo2. What's going in there?
By writing Spinner::<&'a i32>::spin, we force the compiler to use a specific implementation of the Spinner trait. And the signature of Spinner::<&'a i32>::spin is fn spin(&self, value: &'a i32). Period. The lifetime 'a is given by the caller; foo can't choose it. Thus we have to pass a reference that lives for at least 'a. That's why the compiler error happens.
So why does foo1 compile? As a reminder:
fn foo1<'a>(t: &'a Planet<&'a i32>) {
let x: i32 = 10;
t.spin(&x);
}
Here, the lifetime 'a is also given by the caller and cannot be chosen by foo1. But, foo1 can chose which impl of Spinner to use! Note that impl<T> Spinner<T> for Planet<T> basically defines infinitely many specific implementations (one for each T). So the compiler also knows that Planet<&'x i32> does implement Spinner<&'x i32> (where 'x is the specific lifetime of x in the function)!
Now the compiler just has to figure out if it can turn Planet<&'a i32> into Planet<&'x i32>. And yes, it can, because most types are variant over their generic parameters and thus Planet<&'a i32> is a subtype of Planet<&'x i32> if 'a is a subtype of 'x (which it is). So the compiler just "converts" t to Planet<&'x i32> and then the Spinner<&'x i32> impl can be used.
Fantastic! But now to the main part: why doesn't foo2 compile then? Again, as a reminder:
fn foo2<'a>(t: &'a Spinner<&'a i32>) {
let x: i32 = 10;
t.spin(&x);
}
Again, 'a is given by the caller and foo2 cannot chose it. Unfortunately, now we already have a specific implementation! Namely Spinner<&'a i32>. We can't just assume that the thing we were passed also implements Spinner<&'o i32> for any other lifetime 'o != 'a! Traits are invariant over their generic parameters.
In other words: we know we have something that can handle references which live at least as long as 'a. But we can't assume that the thing we were handed can also handle lifetimes shorter than 'a!
As an example:
struct Star;
impl Spinner<&'static i32> for Star {
fn spin(&self, value: &'static i32) {}
}
static SUN: Star = Star;
foo2(&SUN);
In this example, 'a of foo2 is 'static. And in fact, Star implements Spinner only for 'static references to i32.
By the way: this is not specific to trait objects! Let's look at this fourth version of foo:
fn foo4<'a, S: Spinner<&'a i32>>(t: &'a S) {
let x: i32 = 10;
t.spin(&x);
}
Same error once again. The problem is, again, that the Spinner impl is already fixed! As with the trait object, we only know that S implements Spinner<&'a i32>, not necessarily more.
HRTB to the rescue?
Using higher ranked trait bounds resolves the issue:
fn foo2(t: &for<'a> Spinner<&'a i32>)
and
fn foo4<S: for<'a> Spinner<&'a i32>>(t: &S)
As it's hopefully clear from the explanation above, this works because we the specific impl of Spinner isn't fixed anymore! Instead, we again have infinitely many impls to choose from (one for each 'a). Thus we can choose the impl where 'a == 'x.

Related

How do I return a reversed iterator?

I was writing some code where I want to use an iterator, or its reversed version depending on a flag, but the straightforward code gives an error
pub fn eggs<I,T>(iter:I)->Box<dyn Iterator<Item=T>>
where I:Iterator<Item=T>+DoubleEndedIterator
{
Box::new(iter.rev())
}
pub fn bacon<I,T>(iter:I, reverse:bool) -> Box<dyn Iterator<Item=T>>
where I:Iterator<Item=T>+DoubleEndedIterator
{
if reverse {
Box::new(iter.rev())
} else {
Box::new(iter)
}
}
fn main()
{
let pants:String = "pants".into();
eggs(pants.chars());
}
fails to compile:
error[E0310]: the parameter type `I` may not live long enough
--> src/main.rs:5:5
|
2 | pub fn eggs<I,T>(iter:I)->Box<dyn Iterator<Item=T>>
| - help: consider adding an explicit lifetime bound...: `I: 'static`
...
5 | Box::new(iter.rev())
| ^^^^^^^^^^^^^^^^^^^^ ...so that the type `Rev<I>` will meet its required lifetime bounds
With my limited understanding of Rust, I'm not sure where those lifetime bounds are coming from. There aren't any on the Iterator trait, or the Rev struct, and the parameter is being moved.
What is the proper way to declare these sorts of functions given that 'static isn't really an option.
rust playground
This doesn't have to do with .rev() at all, but with returning Box<dyn Iterator>:
// error[E0310]: the parameter type `I` may not live long enough
fn boxed_iter<I, T>(iter: I) -> Box<dyn Iterator<Item = T>>
// - help: consider adding an explicit lifetime bound...: `I: 'static`
where
I: Iterator<Item = T>,
{
Box::new(iter)
// ^^^^^^^^^^^^^^ ...so that the type `I` will meet its required lifetime bounds
}
The reason for this is that trait objects like Box<dyn Trait> have an implicit 'static lifetime if not specified. So when the compiler tries to cast Box<I> to Box<dyn Iterator>, it fails if I is does not also have a 'static lifetime. (There are some more specific rules if the trait contains lifetimes itself; you can read about those in more detail here.)
If you instead want a shorter lifetime, you need to specify it explicitly as Box<dyn 'a + Trait>. So for example:
fn boxed_iter<'a, I, T>(iter: I) -> Box<dyn 'a + Iterator<Item = T>>
where
I: 'a + Iterator<Item = T>,
{
Box::new(iter)
}
Frxstrem's answer is excellent. I just want to add that, if you know that the return value of your function has a specific concrete type, you can use the special impl trait syntax.
In the case of your eggs function, the return type is probably something like Rev<I>. That type, on its own, isn't very illuminating, but we know that such a type exists and the only thing we care about is that it's an iterator, so we can write
pub fn eggs<I,T>(iter:I) -> impl Iterator<Item=T> + DoubleEndedIterator
where I: Iterator<Item=T> + DoubleEndedIterator {
iter.rev()
}
Now the compiler still understands that there is a single concrete type and will act accordingly (no need to box the value or have dynamic dispatch), but we as the programmers still only have to care about the Iterator and DoubleEndedIterator aspects of it. Zero-cost abstraction at its finest.
Your bacon function can't benefit from this, as it could return either an I or a Rev<I> depending on input, so the dynamic dispatch is actually necessary. In that case, you'll need to follow Frxstrem's answer to correctly box your iterator.

What does 'impl MyTrait' do without 'for MyStruct' in Rust? [duplicate]

While trying to understand the Any trait better, I saw that it has an impl block for the trait itself. I don't understand the purpose of this construct, or even if it has a specific name.
I made a little experiment with both a "normal" trait method and a method defined in the impl block:
trait Foo {
fn foo_in_trait(&self) {
println!("in foo")
}
}
impl dyn Foo {
fn foo_in_impl(&self) {
println!("in impl")
}
}
impl Foo for u8 {}
fn main() {
let x = Box::new(42u8) as Box<dyn Foo>;
x.foo_in_trait();
x.foo_in_impl();
let y = &42u8 as &dyn Foo;
y.foo_in_trait();
y.foo_in_impl(); // May cause an error, see below
}
Editor's note
In versions of Rust up to and including Rust 1.15.0, the line
y.foo_in_impl() causes the error:
error: borrowed value does not live long enough
--> src/main.rs:20:14
|
20 | let y = &42u8 as &Foo;
| ^^^^ does not live long enough
...
23 | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
This error is no longer present in subsequent versions, but the
concepts explained in the answers are still valid.
From this limited experiment, it seems like methods defined in the impl block are more restrictive than methods defined in the trait block. It's likely that there's something extra that doing it this way unlocks, but I just don't know what it is yet! ^_^
The sections from The Rust Programming Language on traits and trait objects don't make any mention of this. Searching the Rust source itself, it seems like only Any and Error use this particular feature. I've not seen this used in the handful of crates where I have looked at the source code.
When you define a trait named Foo that can be made into an object, Rust also defines a trait object type named dyn Foo. In older versions of Rust, this type was only called Foo (see What does "dyn" mean in a type?). For backwards compatibility with these older versions, Foo still works to name the trait object type, although dyn syntax should be used for new code.
Trait objects have a lifetime parameter that designates the shortest of the implementor's lifetime parameters. To specify that lifetime, you write the type as dyn Foo + 'a.
When you write impl dyn Foo { (or just impl Foo { using the old syntax), you are not specifying that lifetime parameter, and it defaults to 'static. This note from the compiler on the y.foo_in_impl(); statement hints at that:
note: borrowed value must be valid for the static lifetime...
All we have to do to make this more permissive is to write a generic impl over any lifetime:
impl<'a> dyn Foo + 'a {
fn foo_in_impl(&self) { println!("in impl") }
}
Now, notice that the self argument on foo_in_impl is a borrowed pointer, which has a lifetime parameter of its own. The type of self, in its full form, looks like &'b (dyn Foo + 'a) (the parentheses are required due to operator precedence). A Box<u8> owns its u8 – it doesn't borrow anything –, so you can create a &(dyn Foo + 'static) out of it. On the other hand, &42u8 creates a &'b (dyn Foo + 'a) where 'a is not 'static, because 42u8 is put in a hidden variable on the stack, and the trait object borrows this variable. (That doesn't really make sense, though; u8 doesn't borrow anything, so its Foo implementation should always be compatible with dyn Foo + 'static... the fact that 42u8 is borrowed from the stack should affect 'b, not 'a.)
Another thing to note is that trait methods are polymorphic, even when they have a default implementation and they're not overridden, while inherent methods on a trait objects are monomorphic (there's only one function, no matter what's behind the trait). For example:
use std::any::type_name;
trait Foo {
fn foo_in_trait(&self)
where
Self: 'static,
{
println!("{}", type_name::<Self>());
}
}
impl dyn Foo {
fn foo_in_impl(&self) {
println!("{}", type_name::<Self>());
}
}
impl Foo for u8 {}
impl Foo for u16 {}
fn main() {
let x = Box::new(42u8) as Box<dyn Foo>;
x.foo_in_trait();
x.foo_in_impl();
let x = Box::new(42u16) as Box<Foo>;
x.foo_in_trait();
x.foo_in_impl();
}
Sample output:
u8
dyn playground::Foo
u16
dyn playground::Foo
In the trait method, we get the type name of the underlying type (here, u8 or u16), so we can conclude that the type of &self will vary from one implementer to the other (it'll be &u8 for the u8 implementer and &u16 for the u16 implementer – not a trait object). However, in the inherent method, we get the type name of dyn Foo (+ 'static), so we can conclude that the type of &self is always &dyn Foo (a trait object).
I suspect that the reason is very simple: may be overridden or not?
A method implemented in a trait block can be overridden by implementors of the trait, it just provides a default.
On the other hand, a method implemented in an impl block cannot be overridden.
If this reasoning is right, then the error you get for y.foo_in_impl() is just a lack of polish: it should have worked. See Francis Gagné's more complete answer on the interaction with lifetimes.

Explicit lifetime for Vec to slice conversation

I want a callback on changes inside a list, so I created simple example:
struct Foo;
struct FooList {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(& mut [Foo])>>,
}
impl FooList {
/*
pub fn register_on_change_cb2<F>(&mut self, cb: F) where F: FnMut(&mut [Foo]) {
self.on_change_cb.push(Box::new(cb));
}*/
pub fn register_on_change_cb(&mut self, cb: Box<FnMut(&mut [Foo])>) {
self.on_change_cb.push(cb);
}
pub fn push(&mut self, foo: Foo) {
self.list.push(foo);
self.on_change();
}
fn on_change(&mut self) {
for cb in &mut self.on_change_cb {
cb(&mut self.list);
}
}
}
I don't give any explicit hint to the compiler about lifetimes here: Vec<Box<FnMut(& mut [Foo])>>, so what lifetimes will the compiler use here? If I change the code like this:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&'a mut [Foo])>>,
}
impl<'a> FooList<'a> {
I get a compile time error:
error[E0495]: cannot infer an appropriate lifetime for borrow
expression due to conflicting requirements
How can I explicitly set the lifetimes in some way such that the lifetime of & mut [Foo] for the callback is less than, but not equal to the lifetime of the whole FooList object?
I have commented register_on_change_cb2, I want to allow calling register_on_change_cb without usage of Box::new but failed. If you uncomment register_on_change_cb2, you get the error:
error[E0310]: the parameter type F may not live long enough
How can I fix this error without the requirement of a 'static lifetime for callback? I just want to call Box::new on my side.
I'm going to try to answer your questions 1 and 3, because question 2 is either redundant or orthogonal to the others, and I can't tell what you really want to achieve by it. Perhaps it deserves a question of its own.
If you have a function that takes a reference, but it doesn't need any lifetime information about the reference, it must be able to accept a reference of any lifetime. Here's the explicit syntax for that (this is what the compiler infers from the code you wrote):
on_change_cb: Vec<Box<for<'b> FnMut(&'b mut [Foo])>>,
This is called a higher ranked trait bound or HRTB for short. They're mostly useful for the Fn traits, which is why they exist.
If the type of on_change_cb is Vec<Box<FnMut(&mut [Foo])>>, which doesn't carry any lifetime information, then it must not contain any references (except 'static references). You need to say that the type implementing FnMut may also contain (non-'static) references, as long as they outlive some lifetime 'a:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&mut [Foo]) + 'a>>,
}
This reads something like: "For each FooList object, there is a lifetime 'a such that every callback in the FooList contains only references that live for at least 'a." This interpretation may make it easier to write the prototype for register_on_change_cb2: it takes a callback that also contains only references that live for at least 'a.
impl<'a> FooList<'a> {
pub fn register_on_change_cb2<F>(&mut self, cb: F)
where F: FnMut(&mut [Foo]) + 'a
{
self.on_change_cb.push(Box::new(cb));
}
(I think I have the variance of 'a correct now -- a previous version of this answer had it wrong.)
The 'a lifetime lets the compiler guarantee that you never put a callback in the Box (and therefore the Vec) unless it lasts at least as long as the FooList itself. This is important because closures can capture references to values in the enclosing scope, as in the following code (playground link):
let longlived = String::from("hello");
let mut list = FooList {
list: Vec::new(),
on_change_cb: Vec::new(),
};
list.register_on_change_cb2(|_| println!("{}", longlived)); // ok
let shortlived = String::from("hello");
list.register_on_change_cb2(|_| println!("{}", shortlived)); // `shortlived` does not live long enough
list.push(Foo);
In this example, you can't insert the closure that captures shortlived because it doesn't outlive the (inferred) lifetime 'a. But you can insert the closure that captures longlived, because the compiler can infer a lifetime 'a that satisfies both constraints:
'a must outlive list, because list is of type FooList<'a>.
longlived must outlive 'a, because |_| println!("{}", longlived), which borrows longlived, is bounded by 'a in the call to register_on_change_cb2.
If you want to say that the callbacks don't borrow anything by-reference, the 'a lifetime is unnecessary, and in that case you could just add the 'static bound that the compiler suggests:
pub fn register_on_change_cb2<F>(&mut self, cb: F)
where F: FnMut(&mut [Foo]) + 'static

Trait which returns iterator with lifetime bounded by the lifetime of an argument

I have a trait which says that any implementation of Foo needs to provide a method bar which returns an object of some type which implements Iterator<Item = u32>:
trait Foo {
type FooIterator: Iterator<Item = u32>;
fn bar(&self) -> FooIterator;
}
For this case, I believe that the default lifetime elision means that the iterator returned by bar is required to live on its own, without being tied to the lifetime of the Foo it is iterating over. User Habnabit on #rust irc suggested the following way to say that the lifetime of the FooIterator is less than the lifetime of the Foo. i.e. it allows the implementation of the FooIterator to keep a reference to the Foo that it comes from:
trait Foo<'a> {
type FooIterator: Iterator<Item = u32> + 'a;
fn bar<'b: 'a>(&'b self) -> Self::FooIterator;
}
What I really want is the case where the function bar takes an additional argument, and the implementation of FooIterator is allowed to keep a reference to both the Foo and the additional argument. i.e. the lifetime of FooIterator is bounded by the lifetime of the Foo and the lifetime of the additional argument.
My literal translation of this idea would be
trait Zip {}
trait Foo<'a, 'c> {
type FooIterator: Iterator<Item = u32> + 'a + 'c;
// Foo.bar() returns an iterator that has a lifetime less than the Foo
fn bar<'b: 'a, 'd: 'c>(&'b self, &'d Zip) -> Self::FooIterator;
}
But I was told there there is no "good" way to do this. What would be the best way to implement this idiom? What would the above code do exactly?
What you're looking for is associated type constructors, a planned feature that is not yet implemented in Rust. With associated type constructors, your code would look like this:
trait Zip {}
trait Foo {
type FooIterator<'a, 'c>: Iterator<Item = u32> + 'a + 'c;
// Foo.bar() returns an iterator that has a lifetime less than the Foo
fn bar<'a, 'b: 'a, 'c, 'd: 'c>(&'b self, &'d Zip) -> Self::FooIterator<'a, 'c>;
}
Actually, I'm not sure all those lifetimes are necessary, because a &'a T can be coerced to a &'b T where 'a: 'b. Thus, the following might be good enough:
trait Zip {}
trait Foo {
type FooIterator<'a, 'c>: Iterator<Item = u32> + 'a + 'c;
// Foo.bar() returns an iterator that has a lifetime less than the Foo
fn bar<'a, 'c>(&'a self, &'c Zip) -> Self::FooIterator<'a, 'c>;
}
Depending on how you want to use this trait, you may be able to make it work by implementing it for &'a Struct instead of for Struct, thus "hoisting" the responsibility for finding the right lifetime from the trait into the caller.
Remove the lifetime annotation from the trait and change bar so it takes self, plus another argument of the same lifetime:
trait Foo {
type FooIterator: Iterator<Item = u32>;
fn bar(self, other: Self) -> Self::FooIterator;
}
(Removing 'a from the trait is possible because bar consumes the reference instead of reborrowing it -- self doesn't have to outlive the return value anymore because it's been moved into it.)
Then impl it for a reference of lifetime 'a:
impl<'a> Foo for &'a Vec<u32> {
type FooIterator = ...; // something presumably containing 'a
fn bar(self, other: Self) -> Self::FooIterator {
...
}
}
This works because the compiler can limit the lifetime 'a to one for which the impl applies.
Here's a playground link where bar is basically a wrapper around .chain().
I'm ignoring the Zip trait for now because how to incorporate it depends on what it provides. Instead, I suppose that bar only accepts an argument of the same type as Self. However, you can probably add it as well, maybe using the same technique if you need to.

Unable to infer lifetime for borrow expression when using a trait with an explicit lifetime

use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar<'a> {
fn test(&self, arg: BufReader<'a>) {}
}
impl<'a, T: Bar<'a>> Foo {
fn bar(&'a mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
fn main() {}
The code above fails to compile, with the error message:
lifetimes.rs:17:31: 17:40 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
^~~~~~~~~
lifetimes.rs:16:5: 18:6 help: consider using an explicit lifetime parameter as shown: fn baz(&'a self, t: T)
lifetimes.rs:16 fn baz(&self, t: T) {
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
lifetimes.rs:18 }
error: aborting due to previous error
However, if I add the named lifetime parameter, I cannot mutable borrow the buf field after calling test, as seen in fn bar. Commenting out the fn baz and trying to compile results in:
lifetimes.rs:13:22: 13:30 error: cannot borrow `self.buf` as mutable because it is also borrowed as immutable
lifetimes.rs:13 let b = &mut self.buf;
^~~~~~~~
lifetimes.rs:12:32: 12:40 note: previous borrow of `self.buf` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.buf` until the borrow ends
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
^~~~~~~~
lifetimes.rs:14:6: 14:6 note: previous borrow ends here
lifetimes.rs:11 fn bar(&'a mut self, t: T) {
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
lifetimes.rs:13 let b = &mut self.buf;
lifetimes.rs:14 }
^
error: aborting due to previous error
My understanding of this is that by adding the named lifetime 'a to the &'a mut self parameter, the reference taken by BufReader has a lifetime as long as the self reference is valid, which is until the end of the function. This conflicts with the mutable borrow of self.buf on the line after.
However, I am not sure why I need the named lifetime parameter on the self. It seems to me that the BufReader reference should be able to only exist for the lifetime of the t.test method call. Is the compiler complaining because the self.buf borrow must be ensured to live only as long as the &self borrow? How would I go about doing that while still only borrowing it for the lifetime of the method call?
Any help in going about fixing this problem and understanding more about the semantics here would be much appreciated!
Update
So I am still looking into this problem, and I have found this test case and this issue that show basically what I am trying to do. I would very much like to understand why the error pointed to by the test case link is an error.
I can see in the issue rustc output that attempts to point out what the error is, but I am having trouble understanding what exactly it is trying to say.
Removing all explicit lifetimes also works. I've found that I only add lifetimes when I'm sure I need them (i.e. to specifiy that two lifetimes should intersect at a given point which can't be known to the compiler).
I'm not sure exactly what you're going for, but this compiles (on rustc 0.13.0-nightly (cc19e3380 2014-12-20 20:00:36 +0000)).
use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar {
fn test(&self, arg: BufReader) {}
}
impl<T: Bar> Foo {
fn bar(&mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
Edit
I'm going to copy-edit my comment here:
I originally thought that adding a lifetime or generic parameter to the trait / struct / enum was a shorthand for putting it on every method in the trait, but I was wrong. My current understanding is that you add a lifetime to the trait / struct / enum when that item needs to participate in the lifetime, likely because it is storing a reference with that lifetime.
struct Keeper<'a> {
counts: Vec<&'a i32>,
}
impl<'a> Keeper<'a> {
fn add_one(&mut self, count: &'a i32) {
if *count > 5 {
self.counts.push(count);
}
}
fn add_two<'b>(&mut self, count: &'b i32) -> i32 {
*count + 1
}
}
fn main() {
let mut cnt1 = 1;
let mut cnt2 = 2;
let mut k = Keeper { counts: Vec::new() };
k.add_one(&cnt1);
k.add_two(&cnt2);
// cnt1 += 1; // Errors: cannot assign to `cnt1` because it is borrowed
cnt2 += 1; // Just fine
println!("{}, {}", cnt1, cnt2)
}
Here, we've added a lifetime to Keeper because it might store the reference it is given. The borrow checker must assume that the reference is stored for good when we call add_one, so once we call that method, we can no longer mutate the value.
add_two, on the other hand, creates a fresh lifetime that can only be applied to that function invocation, so the borrow checker knows that once the function returns, it is the One True Owner.
The upshot is, if you need to store a reference, then there's nothing you can do at this level. Rust can't make sure you are safe, and that's something it takes seriously.
However, I bet you don't need to store the reference. Move the <'a, T: Bar<'a>> from the impl to the fn and you'll be good to go.
Said another way: I bet you should never have impl<A> if your trait or struct don't require it. Put the generics on the methods instead.
Original
This compiles, but I'm not 100% sure it does what you intended:
impl Foo {
fn baz<'a, T: Bar<'a>>(&'a self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
I fell into this trap myself, so I'll paste what I was told:
Everything in the impl block is parameterized. I've actually never
seen type parameters added to impl blocks themselves that aren't part
of the trait or type definition. It's far more common to parameterize
the individual methods that need it.
Perhaps other comments / answers can help explain in further detail.

Resources