Confusing error in Rust with trait object lifetime - rust

Can anyone tell what the problem is with the following code? The compiler is complaining about lifetimes, but the error message makes absolutely no sense. I've tried everything I could think of, but nothing seems to help.
use std::borrow::BorrowMut;
trait Trait<'a> {
fn accept(&mut self, &'a u8);
}
struct Impl<'a>{
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {
fn accept(&mut self, inp: &'a u8) { self.myref = Some(inp); }
}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl{myref: None})
}
fn user<'a>(obj: &mut Trait<'a>) {}
fn parent<'a>(x: &'a u8) {
let mut pool = new();
user(pool.borrow_mut());
}
The compiler error is
error: `pool` does not live long enough
--> src/wtf.rs:22:10
|
22 | user(pool.borrow_mut());
| ^^^^ does not live long enough
23 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
Which makes absolutely no sense. How is the borrower outliving anything? I'm not even using the borrowed value!

Ok, this does make sense, but it's hard to see due to lifetime elision. So, here's your code with all the lifetimes written out explicitly, and with irrelevant details culled:
use std::borrow::BorrowMut;
trait Trait<'a> {}
struct Impl<'a> {
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'b)) {}
fn parent() {
/* 'i: */ let mut pool/*: Box<Trait<'x> + 'x>*/ = new();
/* 'j: */ let pool_ref/*: &'i mut Box<Trait<'x> + 'x>*/ = &mut pool;
/* BorrowMut<T>::borrow_mut<'d>(&'d mut Self) -> &'d mut T */
/* 'k: */ let pool_borrow/*: &'i mut (Trait<'x> + 'x)*/ = Box::borrow_mut(pool_ref);
user(pool_borrow);
}
Now, from the perspective of the last line of parent, we can work out the following equivalences by just reading the definition of user and substituting the lifetimes we have in parent:
'a = 'x
'b = 'i
'b = 'x
Furthermore, this lets us conclude that:
'x = 'i
This is the problem. Because of the way you've defined user, you've put yourself in a situation where the lifetime of the pool_ref borrow (which is equal to the lifetime of the pool storage location you're borrowing from) must be the same as the lifetime 'x being used in the thing being stored in pool.
It's a bit like the Box being able to have a pointer to itself before it exists, which doesn't make any sense.
Either way, the fix is simple. Change user to actually have the correct type:
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'a)) {}
This matches the type produced by new. Alternately, just don't use borrow_mut:
user(&mut *pool)
This works because it is "re-borrowing". Calling borrow_mut translates the lifetimes more or less directly, but re-borrowing allows the compiler to narrow the borrows to shorter lifetimes. To put it another way, explicitly calling borrow_mut doesn't allow the compiler enough freedom to "fudge" the lifetimes to make them all line up, re-borrowing does.
As a quick aside:
I'm not even using the borrowed value!
Irrelevant. Rust does type- and lifetime-checking entirely locally. It never looks at the body of another function to see what it's doing; it goes on the interface alone. The compiler neither checks, nor cares, what you're doing inside a different function.

Note that there's more to the error message:
error: `pool` does not live long enough
--> src/main.rs:25:10
|>
25 |> user(pool.borrow_mut());
|> ^^^^
note: reference must be valid for the block at 23:25...
--> src/main.rs:23:26
|>
23 |> fn parent<'a>(x: &'a u8) {
|> ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 24:25
--> src/main.rs:24:26
|>
24 |> let mut pool = new();
|> ^
Let's look at user:
fn user<'a>(obj: &mut Trait<'a>) {}
This says that it will accept a mutable reference (with an unnamed lifetime) to a trait object parameterized with the lifetime 'a.
Turning to new, I'd say the method is highly suspicious:
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
This says that it will return a boxed trait object with whatever lifetime the caller specifies. That basically never makes sense.
All that said, I'm not clear why the code chooses to use borrow_mut. I would have written that more directly:
user(&mut *pool);
This dereferences the Box<Trait> to get a Trait, then takes a mutable reference, yielding &mut Trait, which compiles.
I cannot currently explain why BorrowMut differs in behavior.

I'm not sure why this error happens, but I can give solutions!
First, it seems that using borrow_mut unnecessarily restricts the lifetime of the returned reference. Using operators to create the reference solves the error.
fn parent() {
let mut pool = new();
user(&mut *pool);
}
However, if we don't do that, we can solve the error by adding a lifetime bound to the Trait object in user's obj argument.
fn user<'a>(obj: &mut (Trait<'a> + 'a)) {}

Related

How can I make `Box<dyn Iterator>` peekable and avoid lifetime errors?

I have the following type definition:
pub struct UTF8Chars {
bytes: Peekable<Box<dyn Iterator<Item = u8>>>,
}
Now I'm wondering how to actually create an instance of this struct.
I've tried (and yes, this is inside a trait implementation if that is an important detail):
impl<'a> ToUTF8Chars for &'a str {
fn utf8_chars(self) -> UTF8Chars {
let bytes = Box::new(self.bytes()).peekable();
UTF8Chars { bytes }
}
}
That gives me the error:
expected struct `Peekable<Box<(dyn Iterator<Item = u8> + 'static)>>`
found struct `Peekable<Box<std::str::Bytes<'_>>>`
Playground
Forgive me if I try weird things, but I haven't gotten the hang of this intricate trait stuff yet. For all I know, rust-analyzer was telling me that Bytes in fact an impl Iterator<Item = u8>. So, next thing I tried was casting it first:
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
UTF8Chars { bytes: bytes.peekable() }
That sort of works, but now the borrow checker is complaining:
impl<'a> ToUTF8Chars for &'a str {
-- lifetime `'a` defined here
fn utf8_chars(self) -> UTF8Chars {
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`
I'm not exactly sure what is going out of scope here... as far as I know, I own the result from .bytes() (I also tried with an additional .clone() in case that assumption was incorrect), I own the Box, the Box is passed to Peekable, and finally Peekable is passed to UTF8Chars. What exactly is the issue here? Why do I somehow need to outlive static...?
I found this issue that seems similar, sadly no answer: Peekable of an Iterator in struct.
Why I want to do this?
Well, mainly because I don't really care, or am unable to care what exactly the underlying data is. I just need to know that I can .peek(), and .next(), etc. This is, because sometimes I want to assign different things to self.bytes. For example, Chain<...>, or Copied<...> instead of a simple vec::IntoIter<...>.
If there is an alternative approach to this, I'm happy to hear about it.
So, next thing I tried was casting it first:
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
This is the right thing to do in this situation, though I would write it with a type annotation on the let, instead of as.
let bytes: Box<dyn Iterator<Item = u8>> = Box::new(self.bytes());
In particular, there must be a point at which the unsizing coercion from Box<Bytes> to Box<dyn Iterator<Item = u8>> happens, and that point must be before the Box is contained in something else (because it actually produces a different Box, one with a vtable pointer added).
In some cases, just as _ (unspecified type) is sufficient to prompt the compiler into not immediately concluding that the type is the same as the incoming type.
I'm not exactly sure what is going out of scope here...
Every trait object (dyn) type has a lifetime, often implicit. This lifetime specifies how long instances of that type are guaranteed valid — or, from the opposite perspective, what references the trait object is allowed to borrow/contain.
When you don't specify that lifetime, and the trait object is in a Box, lifetime elision rules make that lifetime be 'static. That's why you have an error: you're trying to put a Bytes<'a> in a place where 'static is required.
In order to allow your boxed iterator to borrow, you must define the types and traits to have a lifetime.
use core::iter::Peekable;
pub struct UTF8Chars<'a> {
bytes: Peekable<Box<dyn Iterator<Item = u8> + 'a>>,
}
trait ToUTF8Chars<'a> {
fn utf8_chars(self) -> UTF8Chars<'a>;
}
impl<'a> ToUTF8Chars<'a> for &'a str {
fn utf8_chars(self) -> UTF8Chars<'a> {
let bytes: Box<dyn Iterator<Item = u8> + 'a> = Box::new(self.bytes());
UTF8Chars {
bytes: bytes.peekable(),
}
}
}
If you don't want to add a lifetime, then you must only use owning iterators (e.g. String::into_bytes(s).into_iter()). With the lifetime, you can use both owning and borrowing iterators.
The issue is that dyn Trait types are actually dyn Trait + 'static by default, which means they're not allowed to borrow any data. That's a problem for you because the iterator returned by calling bytes() on a &'a str borrows from that str and thus cannot outlive 'a. But 'a doesn't outlive 'static so you can't make a dyn Iterator + 'static from it.
As you might have guessed, the solution here is adding some more general lifetime bounds, first to the struct:
pub struct UTF8Chars<'a> {
// ^^^^ now generic over 'a
bytes: Peekable<Box<dyn Iterator<Item = u8> + 'a>>,
// ------------------------^^^^
// the iterator is now allowed to borrow data for 'a
}
Then to the trait:
trait ToUTF8Chars {
fn utf8_chars<'a>(self) -> UTF8Chars<'a> where Self: 'a;
// ^^^^ also generic over 'a ^^^^^^^^ self can borrow data for 'a
}
Depending on your exact use case, using a borrowed receiver might be nicer, though:
trait ToUTF8Chars {
fn utf8_chars<'a>(&'a self) -> UTF8Chars<'a>;
// ^^^^ just borrow `self` for 'a
}
I'm sure there's a cases where these two aren't the same (object safety, probably?) but I can't pin point a specific situation off the top of my head.
And finally the implementation:
impl<'b> ToUTF8Chars for &'b str {
fn utf8_chars<'a>(self) -> UTF8Chars<'a> where Self: 'a {
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
UTF8Chars { bytes: bytes.peekable() }
}
}
or
impl ToUTF8Chars for str {
fn utf8_chars<'a>(&'a str) -> UTF8Chars<'a> {
let bytes = Box::new(self.bytes()) as Box<dyn Iterator<Item = u8>>;
UTF8Chars { bytes: bytes.peekable() }
}
}
for the alternative version of ToUTF8Chars.

Lifetime and closures and continuation passing style

I'm playing with Rust closures, trying to get a feeling for them, and one task I set for myself was to implement an in-order traversal with continuation-passing-style. Usually something I can do in about an hour in other languages, but here I've managed to get stuck on how to manage the lifetime of a closure I use in callback.
I've defined a binary tree like this, which is pretty straightforward:
// A node is a tuple of (left, value, right)
struct Node<T>(pub Tree<T>, pub T, pub Tree<T>);
// A tree is an optional pointer to a node
type Tree<T> = Option<Box<Node<T>>>;
and I can do a direct recursive traversal the way I would expect:
// Direct recursion.
// The <T: Copy> is needed because we copy values into
// the result vector. For other usages we might not need it
fn inorder<T: Copy>(t: &Tree<T>, res: &mut Vec<T>) {
// If t is not empty it is Some(node)
if let Some(node) = t {
// Pull out the values of the node.
// In the development branch of Rust there is
// a nicer syntax, but this is how it is now
let Node(left, val, right) = node.as_ref();
inorder(left, res);
res.push(*val);
inorder(right, res);
}
}
To do it with continuations, however, I need to define closures to manage the rest of the traversal and pass those along with a tail-recursion, and my immediate solution looked not much different from my current one:
// Ideally, we wouldn't need to pass the vector along with the closures
// but Rust won't let us hold on to a mutable reference in a closure if
// another closure also has a mutable reference, so we pass the vector
// from continuation to continuation instead.
fn cps_rec<T: Copy>(t: &Tree<T>, res: &mut Vec<T>,
k: Box<dyn FnOnce(&mut Vec<T>)>)
{
match t {
None => { k(res) },
Some(node) => {
let Node(left, val, right) = node.as_ref();
let after_left = |v: &mut Vec<T>| {
// After we have gone left, add v and go right,
// calling k when we are done
v.push(*val);
cps_rec(right, v, k);
};
cps_rec(left, res, Box::new(after_left));
}
}
}
fn cps<T: Copy>(t: &Tree<T>) -> Vec<T> {
let mut res = vec![];
cps_rec(t, &mut res, Box::new(|_| ()));
res
}
Playground
The problem is in the recursion cps_rec(left, res, after_left) where the lifetime of the closure doesn't match the constraint. (I think, I can't say I fully understand exactly what Rust is complaining about, but the problem goes away as soon as I make the closure's body empty, so it is something in the inferred lifetime there that is messing things up). I first suspected that it was the lifetime of val or right that was fighting me, but it doesn't help to put move in front of the closure after dereferencing them
fn cps_rec<T: Copy>(t: &Tree<T>, res: &mut Vec<T>,
k: Box<dyn FnOnce(&mut Vec<T>)>)
{
match t {
None => { k(res) },
Some(node) => {
let Node(left, val, right) = node.as_ref();
let val = *val;
let right = *right;
let after_left = move |v: &mut Vec<T>| {
// After we have gone left, add v and go right,
// calling k when we are done
v.push(val);
cps_rec(&right, v, k);
};
cps_rec(left, res, Box::new(after_left));
}
}
}
Playground
so I can't work out what the problem is, or how to tell Rust that this closure will survive long enough to complete the recursion...
I then tried using a generic type for the continuation, seeing if that would make Rust resolve the issue for me:
fn cps_rec<'a, T: Copy, Cont>(t: &'a Tree<T>, res: &'a mut Vec<T>, k: Cont)
where Cont: FnOnce(&'a mut Vec<T>)
{
match t {
None => { k(res) },
Some(node) => {
let Node(left, val, right) = node.as_ref();
let after_left = |v: &'a mut Vec<T>| {
// After we have gone left, add v and go right,
// calling k when we are done
v.push(*val);
cps_rec(right, v, k);
};
cps_rec(left, res, Box::new(after_left));
}
}
}
Playground
but that breaks the compilation when the type checker has to recurse on the type inference. Maybe not surprising since the type of the closure probably depends on the inferred type of the recursion.
Is there something I can do to fix this, or is the idea dead on arrival and I have to try a completely different approach if I want to make something along those lines?
The lifetime problem is becaue Box<dyn FnOnce(&mut Vec<T>)> is actually, with lifetimes explicitly specified, Box<dyn FnOnce(&mut Vec<T>) + 'static>. That is, it requires the closures to be 'static. A closure is static if everything it captures is 'static. Of course an empty closure fulfills this condition - it captures nothing, so it worked if you emptied its body.
However, your closure captures over non-'static references - val and right. I'll soon explain why copying them doesn't work.
The solution is simple: we don't really need the closure to be 'static; we can be fine even if it won't be - we don't store it or something. To express that to the compiler, we need to change Box<dyn FnOnce(&mut Vec<T>)> to Box<dyn FnOnce(&mut Vec<T>) + '_> (playground). That's it. '_ is the explicitly elided lifetime: it tells the compiler "figure the right lifetime out yourself". Usually the compiler does that automatically, but with dyn Trait he sometimes gives up and just uses 'static. The lifetime is inferred according to the lifetime elision rules; in this case, it introduces a new lifetime, like if we wrote:
fn cps_rec<'elided_lifetime, T: Copy>(
t: &Tree<T>,
res: &mut Vec<T>,
k: Box<dyn FnOnce(&mut Vec<T>) + 'elided_lifetime>,
) { ... }
What confuses here is the compiler's error message. It'd be clearer if you'd followed the compiler's suggestion and put T: 'static (playground):
error: lifetime may not live long enough
--> src/lib.rs:17:32
|
6 | fn cps_rec<T: Copy + 'static>(t: &Tree<T>, res: &mut Vec<T>, k: Box<dyn FnOnce(&mut Vec<T>)>) {
| - let's call the lifetime of this reference `'1`
...
17 | cps_rec(left, res, Box::new(after_left));
| ^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
This is what I said. 'static is required because of the closure's implied 'static bound.
But the compiler is has something more important to tell you (or rather, yell at you). It thinks: "given that the closure requires 'static, those references are obviously 'static. This user isn't lying to me, he's a good citizen!" Only later it'll realize it was wrong, but it will never get to this "later" because it will stop compilation due to errors earlier. But as of now it thinks, "given that those references are obviously 'static, they're &'static T (for val, or &'static Option<Box<T>> for right). But for &'static T to be valid, T: 'static must hold (imagine a reference like &'long &'short i32: you'll be able to access it for 'long, but as long as 'short is over it's invalid, and you will use a dangling reference!). Can I prove that T: 'static always hold? Nope! Well, should emit an error." (You can fill a bug report at https://github.com/rust-lang/rust/issues, the Rust developers will appreciate it even though I'm not sure how much they can do to improve the situation).
Why copying them didn't help? First, the way the compiler thought about it hasn't changed, and so the same error is still emitted. Second, even if we could solve it (for example by specifying T: 'static), there is another error (playground):
error[E0507]: cannot move out of `*right` which is behind a shared reference
--> src/lib.rs:12:34
|
12 | let right: Tree<T> = *right;
| ^^^^^^ move occurs because `*right` has type `Option<Box<Node<T>>>`, which does not implement the `Copy` trait
|
help: consider borrowing the `Option`'s content
|
12 | let right: Tree<T> = *right.as_ref();
| +++++++++
help: consider borrowing here
|
12 | let right: Tree<T> = &*right;
| ~~~~~~~
Hopefully this one is self-explanatory.
About the generic version, your assumption is indeed correct: no language can do recursive CPS with monomorphization, they all use dynamic dispatch (which is equivalent to Box<dyn FnOnce()> (or some GCed version), or to &mut dyn FnMut() or something similar). We will have to instantiate it ad infinitum.

Chaining a sequence of things that are either owned or referenced

I'm attempting to have a trait for things that can either simply contain other things, or create them on demand, given a thing's name. Those contained things should in turn be able to do the same, creating a hierarchy of sorts. Here's a minimal code:
use std::ops::Deref;
pub enum BoxOrRef<'a, T: ?Sized + 'a> {
Boxed(Box<T>),
Ref(&'a T),
}
impl<'a, T: ?Sized + 'a> Deref for BoxOrRef<'a, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
BoxOrRef::Boxed(b) => &b,
BoxOrRef::Ref(r) => r,
}
}
}
pub trait Elem {
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
}
pub trait Table {
fn get_elem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
}
fn resolve_name<'a, T: Table + ?Sized>(
table: &'a T,
name: &[String],
) -> Option<BoxOrRef<'a, dyn Elem>> {
let mut segments = name.iter();
if let Some(first_segment) = segments.next() {
segments.fold(table.get_elem(&first_segment), |res, next| {
res.and_then(|elem| elem.get_subelem(next))
})
} else {
None
}
}
The lifetime checker however, is not satisfied by this:
error[E0597]: `elem` does not live long enough
--> src/lib.rs:33:33
|
33 | res.and_then(|elem| elem.get_subelem(next))
| ^^^^ - borrowed value only lives until here
| |
| borrowed value does not live long enough
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 26:17...
--> src/lib.rs:26:17
|
26 | fn resolve_name<'a, T: Table + ?Sized>(
| ^^
I need to somehow extend lifetimes of the intermediate res's. I guess I could put them in a struct and tweak the return type of resolve_name to return it along with the final element, but that strikes me as rather clumsy way of doing it. Is there a better solution?
The return value of get_subelem can't outlive the &self borrow you used to call it, because the signature of get_subelem says so explicitly:
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
// ^^ ^^
In order to get a BoxOrRef<'a, _>, you have to borrow self for the lifetime 'a. In the caller, elem can't outlive the closure it belongs to, and get_subelem borrows elem, so it can't return a value that can escape that closure either.
You're trying to do something that is unsafe, and the compiler is right to stop you. In theory, table.get_elem could return a Boxed value, and elem.get_subelem could return an internal reference, and then the Box would be dropped when the closure returns, invalidating the reference.
Presumably that doesn't actually happen, so you have to tell the compiler that. One way is to decouple &self from BoxOrRef<'a, _>:
pub trait Elem<'a> {
fn get_subelem(&self, name: &str) -> Option<BoxOrRef<'a, dyn Elem<'a>>>;
}
The above change will make your example compile once you add lifetime parameters to all the Elems, but it puts you in an awkward position when implementing Elem: you can't return a reference to self, so practically everything has to be Boxed.
It's hard to make a good recommendation given the vagueness of the example, but I suggest you take a step back and think about whether BoxOrRef is the right abstraction here. Fundamentally, you can't do anything with a BoxOrRef that you couldn't do with a reference, because the BoxOrRef might be a reference. At the same time, you can't do anything with it that you couldn't do with a Box, because it might be a Box. std::borrow::Cow uses ToOwned to implement Clone and into_owned -- perhaps a similar approach could work for you. (And if you can, maybe just implement ToOwned for dyn Elem and use Cow directly.)

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

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