In Rust, I get the following error:
<anon>:14:9: 14:17 error: `mystruct` does not live long enough
<anon>:14 mystruct.update();
^~~~~~~~
<anon>:10:5: 17:6 note: reference must be valid for the lifetime 'a as defined on the block at 10:4...
<anon>:10 {
<anon>:11 let initial = vec![Box::new(1), Box::new(2)];
<anon>:12 let mystruct = MyStruct { v : initial, p : &arg };
<anon>:13
<anon>:14 mystruct.update();
<anon>:15
...
<anon>:12:59: 17:6 note: ...but borrowed value is only valid for the block suffix following statement 1 at 12:58
<anon>:12 let mystruct = MyStruct { v : initial, p : &arg };
<anon>:13
<anon>:14 mystruct.update();
<anon>:15
<anon>:16 mystruct
<anon>:17 }
error: aborting due to previous error
for the following code:
struct MyStruct<'a>
{
v : Vec<Box<i32>>,
p : &'a i32
}
impl<'a> MyStruct<'a>
{
fn new(arg : &'a i32) -> MyStruct<'a>
{
let initial = vec![Box::new(1), Box::new(2)];
let mystruct = MyStruct { v : initial, p : &arg };
mystruct.update();
mystruct
}
fn update(&'a mut self)
{
self.p = &self.v.last().unwrap();
}
}
fn main() {
let x = 5;
let mut obj = MyStruct::new(&x);
}
(Playground)
I don't understand why mystruct does not live enough. If I comment out the mystruct.update() line it works fine though. What's more is, if I comment out the body of update the code still fails. Why does calling an empty function which borrows a mutable self changes things?
I don't understand which reference is the one the error talks about. Can somebody explain this?
The reference this error talks about is the one which is implicitly created when you call update(). Because update() takes &'a mut self, it means that it accepts a value of type &'a mut MyStruct<'a>. It means that in theory you should call update() like this:
(&mut mystruct).update();
It would be very inconvenient to write this everywhere, and so Rust is able to automatically insert necessary &s, &muts and *s in order to call a method. This is called "autoreference", and the only place it happens is method invocations/field access.
The problem is the definition of update() method:
impl<'a> MyStruct<'a> {
...
fn update(&'a mut self) { ... }
...
}
Here you are requesting that update() receives the value it is called at via a reference with lifetime 'a, where 'a is the lifetime of the reference stored in the structure.
However, when you have a structure value you're calling this method on, there should be already a reference to i32 you stored in this structure. Hence the lifetime of the structure value is strictly smaller than the lifetime designated by the lifetime parameter, so it is just impossible to construct &'a mut MyStruct<'a> with local variables (as in your case).
The solution is to use &mut self instead of &'a mut self:
fn update(&mut self) { ... }
// essentially equivalent to
fn update<'b>(&'b mut self) where 'a: 'b { ... }
// `'b` is a fresh local lifetime parameter
This way the lifetime of the structure in this method call is not tied to the reference this structure contains and can be smaller.
More in-depth explanation follows below.
By itself your definition is not nonsense. For example:
struct IntRefWrapper<'a> {
value: &'a i32
}
static X: i32 = 12345;
static Y: IntRefWrapper<'static> = IntRefWrapper { value: &X };
impl<'a> IntRefWrapper<'a> {
fn update(&'a self) { ... }
}
Y.update();
Here update() invocation won't cause compilation errors because both lifetimes (of Y and of X, reference to which is contained in Y) are 'static.
Let's consider your example, for comparison:
impl<'a> MyStruct<'a> {
fn new(arg : &'a i32) -> MyStruct<'a> {
let initial = vec![Box::new(1), Box::new(2)];
let mystruct = MyStruct { v : initial, p : &arg };
mystruct.update();
mystruct
}
}
Here we have a lifetime parameter, 'a, which is supplied by the caller of the function. For example, the caller could call this function with a static reference:
static X: i32 = 12345;
MyStruct::new(&X); // here &X has static lifetime
However, when update() method is invoked, mystruct lifetime is bounded by the block it is called in:
{
let initial = vec![Box::new(1), Box::new(2)];
let mystruct = MyStruct { v : initial, p : &arg }; // +
// |
mystruct.update(); // |
// |
mystruct // |
}
Naturally, the borrow checker can't prove that this lifetime is the same as the lifetime provided by the caller (and for any possible "external" lifetime it is indeed impossible for them to match), so it throws an error.
When update is defined like this:
fn update(&mut self) { ... }
// or, equivalently
fn update<'b>(&'b mut self) where 'a: 'b { ... }
then when you call it, it is no longer required that the value you call this method on must live exactly as long as 'a - it is sufficient for it to live for any lifetime which is smaller than or equal to 'a - and the lifetime inside the function perfectly matches these requirements. Thus you can call such method on your value, and the compiler won't complain.
Additionally (as noticed in the comments) the following line is indeed invalid and there is no way around it:
self.p = &self.v.last().unwrap();
The borrow check fails here because you're trying to store a reference with lifetime of the structure into the structure itself. In general this can't be done because it has nasty soundness issues. For example, suppose you were indeed able to store this reference into the structure. But now you can't mutate Vec<Box<i32>> in the structure because it may destroy an element which the previously stored references points at, making the code memory unsafe.
It is impossible to check for such things statically, and so it is disallowed on the borrow checking level. In fact, it is just a nice consequence of general borrow checking rules.
Related
I'm having difficulties understanding lifetime parameters in the following code snippet.
struct C {
data: Vec<u32>,
cols: usize
}
trait M<'s> {
fn get(&'s self, r: usize, c: usize) -> u32;
fn get_mut(&'s mut self, r: usize, c: usize) -> &'s mut u32;
}
impl<'s> M<'s> for C {
fn get(&'s self, r: usize, c: usize) -> u32 {
return self.data[self.cols*r+c];
}
fn get_mut(&'s mut self, r: usize, c: usize) -> &'s mut u32 {
return &mut self.data[self.cols*r+c];
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create() -> C {
let data = vec![0u32,1u32,2u32,3u32,4u32,5u32];
return C{data, cols: 3};
}
fn select<'s, 'r: 's>(data: &'r mut dyn M<'s>) {
let mut _val: u32 = 0;
for r in 0..2 {
for c in 0..3 {
_val += *data.get_mut(r,c);
}
}
}
#[test]
fn test_select() {
let mut data = create();
select(&mut data);
}
}
The code snippet does not compile, because it complains that *data is borrowed multiple times in the function fn select<'s, 'r: 's>(data: &'r mut dyn M<'s>) {} when calling get_mut (once in every loop iteration). Even safeguarding the questionable line with curly braces (and thus creating a new context) does not help. My expectation (in both cases) would be, that the mutable borrow of &mut data should end right after the execution of that line.
On the other hand, when I remove all lifetime parameters, everything works as expected.
Can anyone explain what's the difference between the two versions (with and without explicit lifetimes)?
I've also tried to find information about additional lifetime parameters for traits, in particular specifying their meaning, but I have found none. So I assume, that they are just a declaration of the used labels inside the trait. But if that is so, then I would assume that leaving out the lifetime parameters completely and applying the eliding rules would lead to the same result.
There are two things to consider. The first is when you use a generic lifetime for a function, that lifetime must be larger than the life of the function call simply by construction. And the second is since the lifetime self is tied to the lifetime parameter of the trait, when you call .get_mut(), data is borrowed for the lifetime of 's. Combining those two principles, data is borrowed for longer than the function call so you can't call it again (its already mutably borrowed).
On the other hand, when I remove all lifetime parameters, everything works as expected. Can anyone explain what's the difference between the two versions (with and without explicit lifetimes)?
Without a generic lifetime on M, the methods will behave as if defined as so:
impl M for C {
fn get<'a>(&'a self, r: usize, c: usize) -> u32 {
return self.data[self.cols * r + c];
}
fn get_mut<'a>(&'a mut self, r: usize, c: usize) -> &'a mut u32 {
return &mut self.data[self.cols * r + c];
}
}
Thus there is no lifetime associated with the trait; the lifetimes given and returned from the function are generic only to those method calls. And since the compiler can choose a new lifetime 'a for each call and it will always pick the shorted lifetime to satisfy its usage, you can then call data.get_mut() multiple times without worry. And I'll be honest, having the lifetime on the trait didn't make much sense with the original code; as mentioned, the code works with all lifetime annotations removed: playground.
How is returning a mutable reference that is behind an immutable reference, passed as an argument to the function, handled?
struct Foo { i: i32 }
struct Bar<'b> {
f: &'b mut Foo
}
impl<'a: 'b, 'b> Bar<'b> {
fn func(&'a self) -> &'b mut Foo {
self.f
}
}
fn main() {
let mut foo = Foo { i: 1 };
let bar = Bar { f: &mut foo };
bar.func();
}
gives the following error:
error[E0389]: cannot borrow data mutably in a `&` reference
--> src/main.rs:9:14
|
8 | fn func(&'a self) -> &'b mut Foo {
| -------- use `&'a mut self` here to make mutable
9 | self.f
| ^^^^^^ assignment into an immutable reference
I (sort of) understand what the compiler is trying to prevent here. But I am confused with the error message assignment into an immutable reference . What exactly is being assigned into self (or inside ofself.f?) ?
I wrote the following code to simulate this problem and got the same error message, which unlike the above one, I am able to understand. Here's the code:
fn main() {
let mut foo = Foo { i: 1 };
let bar = Bar { f: &mut foo };
let pbar = &bar;
pbar.f.i = 2; // assignment into an immutable reference
}
In the first example, is it trying to move the mutable reference f out of self (since &mut is not a Copy type), treating it as a mutation inside the immutable reference self, hence the error message assignment into an immutable reference?
You can't create a mutable reference from an immutable one. This means that you need to change &self into &mut self:
impl<'a: 'b, 'b> Bar<'b> {
fn func(&'a mut self) -> &'b mut Foo {
self.f
}
}
And now the your variable needs to be mutable so that you can take a mutable reference to it for the method:
let mut bar = Bar { f: &mut foo };
bar.func();
What exactly is being assigned into self (or inside of self.x?) ?
The error message might be a little off. There is no assignment in your code, but you are returning a mutable reference. The only extra thing that a mutable reference would let you do here is to assign self.f or self.f.i.
Definitely this error message can be improved, but it does include a hint to make the &'a self mutable to fix the problem.
Now, your original question:
How is returning a mutable reference that is behind an immutable reference, passed as an argument to the function, handled?
Rust provides a variety of container types for interior mutability, such as Cell and RefCell. These types take the responsibility for ensuring correctness away from the compiler and make it a runtime check. One way of applying a RefCell to your code might be like this:
use std::cell::RefCell;
use std::ops::DerefMut;
struct Foo { i: i32 }
struct Bar<'b> {
// store the data in a RefCell for interior mutability
f: &'b RefCell<Foo>
}
impl<'a: 'b, 'b> Bar<'b> {
// Return a RefMut smart pointer instead of mutable ref, but hide the implementation,
// just exposing it as something that can be mutably dereferenced as a Foo
fn func(&'a self) -> impl DerefMut<Target = Foo> + 'b {
self.f.borrow_mut()
}
}
fn main() {
let foo = RefCell::new(Foo { i: 1 });
let bar = Bar { f: &foo };
let mut f = bar.func();
f.i = 3;
}
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)) {}
I'm afraid this may be very basic but I haven't been able to figure it out on my own. I have this map:
subscriptions_map: HashMap<SubscriptionKey, Subscription<'a>>
and this vector:
subscriptions: Vec<&'a Subscription<'a>>,
I want to insert a value into the HashMap and a reference to the same item into the vector. I've tried to do it like this:
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
self.subscriptions.push(subs);
But it gets this error:
error: borrowed value does not live long enough
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: reference must be valid for the lifetime 'a as defined on the block at 40:70...
pub fn add_subscription(&'a mut self, mut item: Subscription<'a>) {
let id = item.get_id();
let _lock = self.lock.lock().unwrap();
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
...
note: ...but borrowed value is only valid for the block suffix following statement 2 at 45:87
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
self.subscriptions.push(subs);
}
error: aborting due to previous error
I guess my question boils down to: If I have an Option<T<'a>>, how can I get a &'a T?
HashMap.insert() returns the old value for the given key, not the value you just passed. That's not what you want!
After you've inserted an item into the HashMap, you must call HashMap.get() to retrieve a pointer to the value. As HashMap.insert() takes ownership of both the key and the value, we need to pass a clone of id to insert() so we can use the original id for the get() call. (If the type of id is Copy, you may omit the call to clone() and let the compiler copy the value.)
use std::collections::HashMap;
#[derive(Eq, PartialEq, Hash, Clone)]
struct SubscriptionKey;
struct Subscription<'a>(&'a ());
struct Foo<'a> {
subscriptions_map: HashMap<SubscriptionKey, Subscription<'a>>,
subscriptions: Vec<&'a Subscription<'a>>,
}
impl<'a> Foo<'a> {
fn add(&'a mut self, id: SubscriptionKey, item: Subscription<'a>) {
self.subscriptions_map.insert(id.clone(), item);
let subs = self.subscriptions_map.get(&id).unwrap();
self.subscriptions.push(subs);
}
}
fn main() {
let subscription_data = &();
let mut f = Foo {
subscriptions_map: HashMap::new(),
subscriptions: Vec::new(),
};
f.add(SubscriptionKey, Subscription(subscription_data));
}
This works fine, but it falls apart if we try to add another subscription. If we do this:
fn main() {
let subscription_data = &();
let subscription_data2 = &();
let mut f = Foo {
subscriptions_map: HashMap::new(),
subscriptions: Vec::new(),
};
f.add(SubscriptionKey, Subscription(subscription_data));
f.add(SubscriptionKey, Subscription(subscription_data2));
}
the compiler gives the following messages:
<anon>:30:5: 30:6 error: cannot borrow `f` as mutable more than once at a time [E0499]
<anon>:30 f.add(SubscriptionKey, Subscription(subscription_data2));
^
<anon>:30:5: 30:6 help: see the detailed explanation for E0499
<anon>:29:5: 29:6 note: previous borrow of `f` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `f` until the borrow ends
<anon>:29 f.add(SubscriptionKey, Subscription(subscription_data));
^
<anon>:31:2: 31:2 note: previous borrow ends here
<anon>:20 fn main() {
...
<anon>:31 }
^
What's going on? Why does the mutable borrow persist after the first call to Foo::add?
The problem comes from the definition of the subscriptions field. It's defined as a Vec<&'a Subscription<'a>>. Satisfying the 'a in Subscription<'a> is easy, since we receive the object with the correct lifetime in add. Satisfying the 'a in &'a ... is harder, since the Subscription<'a> value doesn't have a fixed address until we insert it into subscriptions_map (in my example, a Subscription<'a> is moved from a local variable in main() to a parameter in Foo::add() to inside self.subscriptions_map).
In order to satisfy the outer 'a, Foo::add() must define its self parameter as &'a mut self. If we defined it as &mut self, we couldn't be sure that the references we get out of subscriptions_map would live long enough (their lifetime could be shorter than 'a).
However, by inserting a &'a Subscription<'a> inside of a Foo<'a>, we are effectively locking down the Foo for further modifications, since we are now storing a borrow from self.subscriptions_map in self.subscriptions. Consider what would happen if we inserted another item in subscriptions_map: how can we be sure that the HashMap won't move its items around in memory? If the HashMap does move our item, the pointer in self.subscriptions wouldn't be updated automatically and would be dangling.
Now, suppose that we have this buggy remove() method:
impl<'a> Foo<'a> {
fn remove(&mut self, id: &SubscriptionKey) {
self.subscriptions_map.remove(id);
}
}
This method compiles fine. However, if we tried to call this on a Foo on which we called add() earlier, then self.subscriptions would contain a dangling reference to an item that used to be in self.subscriptions_map.
So the reason why the mutable borrow persists after calling add() is that, since the 'a in Foo<'a> is equal to the lifetime of the Foo<'a> itself, the compiler sees that the object borrows from itself. As you know, we can't have a mutable borrow and another borrow (mutable or not) active at the same time, so Rust prevents us from taking a mutable borrow on f while f itself retains an active borrow. In fact, since we used a method that takes self by mutable reference, Rust assumes that Foo<'a> stores a mutable reference, even though that's not the case, since Rust only looks at the signatures to determine borrows (this is to ensure that changing a private field from &'a T to &'a mut T doesn't cause borrow checking failures to you and, if you're developing a library, to your users). Since the type of an object never changes, the Foo<'a> is locked for the rest of its lifetime.
Now, what can you do? Clearly, you can't usefully have a Vec<&'a Subscription<'a>> in your struct. HashMap provides a values() iterator, but it enumerates the values in an unspecified order, so it won't help you if you want to enumerate the values in the order in which they were added. Instead of using borrowed pointers, you could use Rc:
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Eq, PartialEq, Hash)]
struct SubscriptionKey;
struct Subscription<'a>(&'a ());
struct Foo<'a> {
subscriptions_map: HashMap<SubscriptionKey, Rc<Subscription<'a>>>,
subscriptions: Vec<Rc<Subscription<'a>>>,
}
impl<'a> Foo<'a> {
fn add(&mut self, id: SubscriptionKey, item: Subscription<'a>) {
let item = Rc::new(item);
self.subscriptions_map.insert(id, item.clone());
self.subscriptions.push(item);
}
}
fn main() {
let subscription_data = &();
let mut f = Foo {
subscriptions_map: HashMap::new(),
subscriptions: Vec::new(),
};
f.add(SubscriptionKey, Subscription(subscription_data));
}
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.