Here is the code:
#[derive(Debug)]
struct Foo {
f: i32,
}
#[derive(Debug)]
struct Bar<'a> {
bar1: &'a Foo,
bar2: &'a Foo,
}
#[allow(unused_variables)]
fn make_bar<'a>(foo1: &'a Foo, foo2: &'a Foo) -> Bar<'a> {
Bar {
bar1: foo1,
bar2: foo2,
}
}
fn extract_bar2<'a>(foo: &'a Foo) -> &'a Foo {
let foo1 = Foo { f: 22 };
let foo2 = make_bar(&foo, &foo1).bar1;
foo2
}
fn main() {
let foo = Foo { f: 11 };
let foo1 = extract_bar2(&foo);
println!("foo1: {:?}", foo1);
}
This gives an error:
error: `foo1` does not live long enough
--> src/main.rs:23:32
|>
23 |> let foo2 = make_bar(&foo, &foo1).bar1;
|> ^^^^
note: reference must be valid for the lifetime 'a as defined on the block at 21:45...
--> src/main.rs:21:46
|>
21 |> fn extract_bar2<'a>(foo: &'a Foo) -> &'a Foo {
|> ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 22:29
--> src/main.rs:22:30
|>
22 |> let foo1 = Foo { f: 22 };
|> ^
The core question is: What does a lifetime parameter actually means in the context of a struct?
More specifically: What are the consequences of having the same lifetime parameter for all fields of a struct? Do their lifetimes have to be exactly the same? Do they have to overlap? If so to what extent should they overlap?
What are the (semantic and practical) differences between the following two structs?
struct Bar<'b> {
bar1: &'b Foo,
bar2: &'b Foo,
}
struct Bar<'a, 'b> {
bar1: &'a Foo,
bar2: &'b Foo,
}
What are the (semantic and practical) differences between the
following two structs?
There is a small example to demonstrate the difference:
#[derive(Debug)]
struct Foo;
#[derive(Debug)]
struct Bar1<'b> {
foo1: &'b Foo,
foo2: &'b Foo,
}
#[derive(Debug)]
struct Bar2<'a, 'b> {
foo1: &'a Foo,
foo2: &'b Foo,
}
fn main() {//'a -->
let foo1 = Foo;
let ref_foo1 =
{//'b -->
let foo2 = Foo;
//error: `foo2` does not live long enough
//replace the Bar1 with Bar2 in the row below to fix error
let bar = Bar1{foo1:&foo1, foo2:&foo2};
bar.foo1
};//--> 'b
println!("ref_foo1={:?}", ref_foo1);
}//--> 'a
The Bar1 truncates the lifetimes of its members to their intersection. So you can't get a reference to the foo1 with lifetime 'a from the Bar1 struct. You get the reference with lifetime 'b.
I should note that the error message in this case is a bit misleading
I will paste an answer from reddit that I am really happy with.
The compiler can combine lifetimes by taking their intersection. That is, if you have 'a and 'b, then there is an intersection 'c of 'a and 'b, during which both lifetimes are 'alive'. I believe it is always the case that this intersection is equal to the shortest of 'a and 'b, because of the way scoping works, but perhaps I am mistaken.
In practice, this means that, when you see a fn<'a>(x: &'a T, y: &'a U) -> &'a V, you can put in a &'static T and a &'b U, and you will get a &'b V, because the intersection of 'static and 'b is 'b.
So, why does your method cause the compiler to complain? Because to the compiler it kinda looks like this (it's not valid syntax):
fn extract_bar2<'a>(foo: &'a Foo) -> &'a Foo {
'b: {
let foo1 = Foo { f: 22 };
'c: { // The next line is wrong
let foo2: &'a Foo = make_bar<'a>(&'a foo, &'b foo1).bar1;
'd: {
return foo2;
}
}
}
}
I've made the scopes more explicit. What happens? The compiler knows that foo2 must have type &'a Foo, because that is what the function returns. So the Bar returned by make_bar must have had lifetime 'a: we couldn't get a &'a Foo out of it otherwise. So we must have called make_bar<'a>. But one of the arguments is wrong! foo2 does not have lifetime 'a, it has lifetime 'b, which is outlived by 'a. If you take the intersection and do this:
let foo2: &'b Foo = make_bar<'b>(&'a foo, &'b foo1).bar1;
then foo2 does not match the return type.
When you use your second definition of Bar, the code will work, because bar1 and bar2 need not have the same lifetimes in that case. So your second Bar definition is strictly more flexible, but in practice you rarely need that extra flexibility, and the extra lifetime annotations are annoying.
Credit to https://www.reddit.com/user/thiez
Related
I have a trait:
trait Foo {
fn bar(&self) -> Cow<str>;
}
And I want to implement it for any type that implements Deref with a target of a type that implements Foo. Basically:
impl<T: Foo, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(std::ops::Deref::deref(self))
}
}
Unfortunately, this gives the error the parameter type T may not live long enough.
My understanding is that T could have a reference within it that has a short lifetime, and the lifetime bound of the return value of Cow<str> is linked to the lifetime of &self due to lifetime elision, which would cause problems.
I'm not sure how I can fix this, since I'm not able to bound any of the lifetimes in bar. I can try to make sure T lives as long as &self, but this doesn't work.
impl<'a, T: Foo + 'a, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&'a self) -> Cow<'a, str> {
<T as Foo>::bar(std::ops::Deref::deref(self))
}
}
I get the error method not compatible with trait since the lifetimes don't match the trait defenition anymore. I've tried all sorts of different ways of adding lifetime bounds and I always get one of those two errors.
I am able to implement Foo for a specific type that implements Deref:
impl<T: Foo> Foo for Box<T> {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(self)
}
}
I'm not sure why that works but the original example doesn't.
The Box version works because of the deref coercion the compiler will do when it sees a reference and expects a different reference.
You can use the same mechanic when using a generic implementor of Deref to ensure that it Derefs to an owned type you can simply add a 'static lifetime bound on T like this:
impl<T: Foo + 'static, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(self)
}
}
playground
Note: there is rarely a need to call methods of std::ops traits directly, they're all just the methods behind Rusts operators, deref for example is the method behind unary *
Update:
Since there is an additional requirement that T might not be static we have to thread through the lifetime like you tried in your second example, like the error you're getting suggest you have to adjust the trait to take a lifetime as well:
use std::borrow::Cow;
trait Foo<'a> {
fn bar(&self) -> Cow<'a, str>;
}
impl<'a, T: Foo<'a>, D: std::ops::Deref<Target = T>> Foo<'a> for D {
fn bar(&self) -> Cow<'a, str> {
<T as Foo>::bar(self)
}
}
struct S<'a> {
val: &'a str,
}
impl<'a> Foo<'a> for S<'a> {
fn bar(&self) -> Cow<'a, str> {
todo!()
}
}
fn main() {
let val = String::from("test");
let s = S { val: &val }; // error: `val` does not live long enough
let b = Box::new(s);
let cow = Foo::bar(&b); // argument requires that `val` is borrowed for `'static`
}
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
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.
I'd like to do something along the following lines:
trait GetRef<'a> {
fn get_ref(&self) -> &'a [u8];
}
struct Foo<'a> {
buf: &'a [u8]
}
impl <'a> GetRef<'a> for Foo<'a> {
fn get_ref(&self) -> &'a [u8] {
&self.buf[1..]
}
}
struct Bar {
buf: Vec<u8>
}
// this is the part I'm struggling with:
impl <'a> GetRef<'a> for Bar {
fn get_ref(&'a self) -> &'a [u8] {
&self.buf[1..]
}
The point of the explicit lifetime variable in the GetRef trait is to allow the return value of get_ref() on a Foo object to outlive the Foo itself, tying the return value's lifetime to that of the lifetime of Foo's buffer.
However, I haven't found a way to implement GetRef for Bar in a way that the compiler accepts. I've tried several variations of the above, but can't seem to find one that works. Is there any there any reason that this fundamentally cannot be done? If not, how can I do this?
Tying a trait lifetime variable to &self lifetime
Not possible.
Is there any there any reason that this fundamentally cannot be done?
Yes. An owning vector is something different than a borrowed slice. Your trait GetRef only makes sense for things that already represent a “loan” and don't own the slice. For an owning type like Bar you can't safely return a borrowed slice that outlives Self. That's what the borrow checker prevents to avoid dangling pointers.
What you tried to do is to link the lifetime parameter to the lifetime of Self. But the lifetime of Self is not a property of its type. It just depends on the scope this value was defined in. And that's why your approach cannot work.
Another way of looking at it is: In a trait you have to be explicit about whether Self is borrowed by a method and its result or not. You defined the GetRef trait to return something that is not linked to Self w.r.t. lifetimes. So, no borrowing. So, it's not implementable for types that own the data. You can't create a borrowed slice referring to a Vec's elements without borrowing the Vec.
If not, how can I do this?
Depends on what exactly you mean by “this”. If you want to write a “common denominator” trait that can be implemented for both borrowed and owning slices, you have to do it like this:
trait GetRef {
fn get_ref(&self) -> &[u8];
}
The meaning of this trait is that get_ref borrows Self and returns a kind of “loan” because of the current lifetime elision rules. It's equivalent to the more explicit form
trait GetRef {
fn get_ref<'s>(&self) -> &'s [u8];
}
It can be implemented for both types now:
impl<'a> GetRef for Foo<'a> {
fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}
impl GetRef for Bar {
fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}
You could make different lifetimes for &self and result in your trait like that:
trait GetRef<'a, 'b> {
fn get_ref(&'b self) -> &'a [u8];
}
struct Foo<'a> {
buf: &'a [u8]
}
impl <'a, 'b> GetRef<'a, 'b> for Foo<'a> {
fn get_ref(&'b self) -> &'a [u8] {
&self.buf[1..]
}
}
struct Bar {
buf: Vec<u8>
}
// Bar, however, cannot contain anything that outlives itself
impl<'a> GetRef<'a, 'a> for Bar {
fn get_ref(&'a self) -> &'a [u8] {
&self.buf[1..]
}
}
fn main() {
let a = vec!(1 as u8, 2, 3);
let b = a.clone();
let tmp;
{
let x = Foo{buf: &a};
tmp = x.get_ref();
}
{
let y = Bar{buf: b};
// Bar's buf cannot outlive Bar
// tmp = y.get_ref();
}
}
This code:
struct Foo<'a> {
value: Option<&'a int>,
parent: Option<&'a Foo<'a>>
}
impl<'a> Foo<'a> {
fn bar<'a, 'b, 'c: 'a + 'b>(&'a self, other:&'b int) -> Foo<'c> {
return Foo { value: Some(other), parent: Some(self) };
}
}
fn main() {
let e = 100i;
{
let f = Foo { value: None, parent: None };
let g:Foo;
{
g = f.bar(&e);
}
// <--- g should be valid here
}
// 'a of f is now expired, so g should not be valid here.
let f2 = Foo { value: None, parent: None };
{
let e2 = 100i;
let g:Foo;
{
g = f2.bar(&e2);
}
// <--- g should be valid here
}
// 'b of e2 is now expired, so g should not be valid here.
}
Fails to compile with the error:
<anon>:8:30: 8:35 error: cannot infer an appropriate lifetime due to conflicting requirements
<anon>:8 return Foo { value: Some(other), parent: Some(self) };
^~~~~
<anon>:7:3: 9:4 note: consider using an explicit lifetime parameter as shown: fn bar<'a, 'b>(&'a self, other: &'b int) -> Foo<'b>
<anon>:7 fn bar<'a, 'b, 'c: 'a + 'b>(&'a self, other:&'b int) -> Foo<'c> {
<anon>:8 return Foo { value: Some(other), parent: Some(self) };
<anon>:9 }
(playpen: http://is.gd/vAvNFi )
This is obviously a contrived example, but it is something I want to do occasionally.
So...
1) How do you combine lifetimes? (ie. Return a Foo which has a lifetime of at least 'a or 'b, which ever is shorter)
2) Is there some way to write tests to asset lifetime compile failures?
(eg. try to compile a #[test] that uses the function in the wrong way and fails with a lifetime error)
The bounds 'c: 'a + 'b means that 'c is at least as long as 'a and as long as 'b. However, in this case, the Foo value is valid for exactly the shortest of 'a and 'b: as soon as the data behind either reference goes out of scope the whole Foo must be invalidated. (This is saying that data that is valid for 'c is valid in the union of 'a and 'b.)
In more concrete terms, say 'b = 'static, then 'c: 'a + 'static means that 'c must also be 'static, so the return value would be Foo<'static>. This is clearly not right as it would be "upgrading" the limited 'a self reference into one that lasts forever.
The correct behaviour here is taking the intersection of the lifetimes: the Foo is only valid while both function parameters are valid. The intersection operation is just labelling the references with the same name:
fn bar<'a>(&'a self, other: &'a int) -> Foo<'a>
Remove all the limetime parameters on bar and use the 'a lifetime parameter from the impl instead.
impl<'a> Foo<'a> {
fn bar(&'a self, other:&'a int) -> Foo<'a> { // '
return Foo { value: Some(other), parent: Some(self) };
}
}
'a will be inferred by the compiler to be the smallest lifetime in which all references are valid.