How to write a function with lifetime constraints for fields? - rust

In the example below, I have a lifetime constraint for the one member. The first call to set_one works, however a second call doesn't:
struct One {
name: String,
}
struct Two<'a> {
one: Option<&'a One>,
}
fn set_one<'a>(two: &'a mut Two<'a>, one: &'a mut One) {
one.name = "something".to_owned();
two.one = Some(one);
}
fn main() {
let mut one = One { name: "".to_owned() };
let mut two = Two { one: None };
set_one(&mut two, &mut one);
set_one(&mut two, &mut one); // error: "two" already borrowed!
}
Playground here.
My understanding is that after the first call to set_one the ownership is given back to the original caller, so when the function returns the borrow for two is gone. But apparently I'm missing something.
What's wrong with the lifetimes of the example above?

For this to make sense you need to recognize that there are 3 lifetimes involved in the calling of set_one
fn set_one<'a, 'b, 'c>(two: &'a mut Two<'b>, one: &'c mut One)
The lifetime of the reference two the lifetime of the reference one and the lifetime of the reference one within Two. These are 'a, 'b and 'c respectively in the signature above.
When you write the signature as
fn set_one<'a>(two: &'a mut Two<'a>, one: &'a mut One)
You are forcing the 3 lifetimes to be the same. And to put it simply this forces these lifetimes to take the 'bigger' lifetime.
Examining the main function:
fn main() {
let mut one = One { name: "".to_owned() }; |
let mut two = Two { one: None }; | Lifetime of 'a
|
set_one(&mut two, &mut one); |
set_one(&mut two, &mut one); |
}
We can see that implicitly now the struct two is a Two<'a> with the lifetime 'a as marked in the code.
Then when we call set_one we force the lifetime of the three parameters to be 'a.
You could declare the lifetimes as:
fn set_one<'a, 'b>(two: &'a mut Two<'b>, one: &'a mut One)
However, this has a problem which is at the root of what you want to do:
fn set_one<'a>(two: &'a mut Two<'a>, one: &'a mut One) {
one.name = "something".to_owned();
two.one = Some(one); // <--- This
}
When you do this two.one = Some(one); you need the reference within Two to live as long as one. Therefore, there is no escaping the fact that you can't call set_one twice because you will need 2 mutable borrows that will live as long as the scope of one in the main function.

Related

Lifetime parameters in a trait

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 to call a function with lifetime from static context

I need to call a function with a lifetime specified on self from a static context like
impl <'w> World<'w> {
pub fn test_with_lifetime(&'w mut self) {
println!("test with lifetime");
}
pub fn test(&mut self) {
println!("test");
}
}
pub fn main(){
let mut world:World = World::new();
let world_rc:Rc<RefCell<World<'static>>> = Rc::new(RefCell::new(world));
let world_in_closure = Rc::clone(&world_rc);
let bx = Box::new(move ||{
if let Ok(mut borrowed_world) = world_in_closure.try_borrow_mut() {
borrowed_world.test_with_lifetime();
}
});
(bx)();
}
and if fails with 'borrowed value does not live long enough...' error.
So I have two questions:
what's difference between &self and &'w self in function definition? Don't they both effectively mean that object lives in the caller's context?
is there a way to make it compile?
playground
pub fn test(&mut self) is not a shortcut of pub fn test(&'w mut self). Rather, it is a shortcut for pub fn test<'a>(&'a mut self).
The difference is where the lifetime is defined: 'w is a part of the type. It is decided by the one who create the instance. And by taking &'w mut self, you usually mean that this function can be called zero (if the instance does not live as long as 'w) or one (if it does) times. More than that it cannot, because because 'w is contained within the type it must be shorter than or equal to the lifetime of the instance. And after you call it with 'w one time, it is mutably borrowed for the rest of its life.
pub fn test<'a>(&'a mut self), on the other hand, means that the caller of the function decides about the lifetime. It can be (and usually is) as short as the whole call, and doesn't need to be the whole instance's lifetime.

What are the differences when getting an immutable reference from a mutable reference with self-linked lifetimes?

struct Foo01<'a> {
val: u32,
str: &'a String,
}
fn mutate_and_share_01<'a>(foo: &'a mut Foo01<'a>) -> &'a Foo01<'a> {
foo
}
fn mutate_and_share_02<'a>(foo: &'a mut Foo01<'a>) -> &'a Foo01 {
foo
}
fn mutate_and_share_03<'a>(foo: &'a mut Foo01) -> &'a Foo01<'a> {
foo
}
fn main() {
let mut foo = Foo01 { val: 16, str: &String::from("Hello ") };
let foo_mut = &mut foo;
//let loan = mutate_and_share_01(foo_mut);
//let loan2 = mutate_and_share_01(foo_mut); //error
//let loan = mutate_and_share_02(foo_mut);
//let loan2 = mutate_and_share_02(foo_mut); //error
let loan = mutate_and_share_03(foo_mut);
let loan2 = mutate_and_share_03(foo_mut); //good
}
What are differences between these mutate_and_share versions?
In cases 1 and 2, you're saying that the function borrows the structure for as long as the structure borrows its parameter:
foo: &'a mut Foo01<'a>
this says "foo is borrowed from 'a" (&'a mut) and "foo borrows its parameter for 'a" (Foo01<'a>).
Meaning as far as rustc is concerned a call to this function will necessarily borrow the input forever, as the structure necessarily borrows its input for the entirety of its own lifetime, and thus you get locked out: you can't "unborrow" the input by dropping it so the second call can't work ever.
In case 3 you're relating the parameter of the output to the internal borrow which isn't really true but works well enough at least for this case. The reality is that the two lifetimes are unrelated:
fn mutate_and_share<'a, 'b>(foo: &'a mut Foo01<'b>) -> &'a Foo01<'b> {
foo
}
Also do note that your third case only works because you're never using loan, so it's immediately dropped before the second line executes. If you do this:
let loan = mutate_and_share_03(foo_mut);
let loan2 = mutate_and_share_03(foo_mut); //good
print("{}", loan.val)
then it's not going to compile because the mutable borrows are overlapping.
Oh, and &String is generally useless. There are use cases for &mut String, but any time you see an immutable reference to a String you'd be better off with an &str. Same with &Vec<T>, not useful, should be &[T].

Aquire &'a T from Option<T<'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));
}

Why doesn't my struct live long enough?

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.

Resources