Multiple lifetimes and move: assignment to borrowed `x` occurs here - reference

I have a struct with a function next() (similar to iterators but not an iterator). This method returns the next state after modification (preserving the original state). So: fn next(&A) -> A.
I started with a simple struct where I didn't need a lifetime (struct A in the example) and I extended it to add a reference to a new struct (struct B).
The problem is that I now need to specify the lifetime for my struct and for some reason my method next() refuses to work anymore.
I suspect that the lifetime of the new struct of every iteration is limited to the scope where it is created and I cannot move it outside of this scope.
Is it possible to preserve the behavior of my next() method?
Try it here
#[derive(Clone)]
struct A(u32);
#[derive(Clone)]
struct B<'a>(u32, &'a u32);
impl A {
fn next(&self) -> A {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}
impl<'a> B<'a> {
fn next(&self) -> B {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}
fn main() {
let mut a = A(0);
for _ in 0..5 {
a = a.next();
}
let x = 0;
let mut b = B(0, &x);
for _ in 0..5 {
b = b.next();
}
}
The error is:
error[E0506]: cannot assign to `b` because it is borrowed
--> src/main.rs:31:9
|
31 | b = b.next();
| ^^^^-^^^^^^^
| | |
| | borrow of `b` occurs here
| assignment to borrowed `b` occurs here

The problem is here:
impl<'a> B<'a> {
fn next(&self) -> B {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}
You didn't specify a lifetime for B, the return type of next. Because of Rust's lifetime elision rules, the compiler infers that you intended this:
impl<'a> B<'a> {
fn next<'c>(&'c self) -> B<'c> {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}
Which means that the return value may not outlive self. Or, put another way, self has to live longer than the B that is returned. Given the body of the function, this is a completely unnecessary requirement because those references are independent of each other. And it causes a problem here:
for _ in 0..5 {
b = b.next();
}
You are overwriting a value that the borrow-checker thinks is still borrowed by the call to next(). Inside next we know that there is no such relationship – the lifetime annotations do not reflect the constraints of what you're actually doing.
So what are the lifetime bounds here?
The lifetimes of references to B are unrelated - each can exist without the other. So, to give the most flexibility to a caller, the lifetime of B should be different from the lifetime of the reference to self in next.
However, each B that is created with next() holds a reference to the same u32 as is held by self. So the lifetime parameter that you give to each B must be the same.
Using explicitly named lifetimes, this is the result of combining both of those things:
impl<'a> B<'a> {
fn next<'c>(&'c self) -> B<'a> {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}
Note that — even though the reference to self here has lifetime 'c — the type of self is B<'a>, where 'a is the lifetime of the &u32 inside. Just the same as the return value.
But actually, the 'c can be elided. So it's really just the same as this:
impl<'a> B<'a> {
fn next(&self) -> B<'a> {
let mut new = self.clone();
new.0 = new.0 + 1;
new
}
}

Related

How do I pass a mutable reference to a method on an object that belongs to that reference?

I have a struct instance A that belongs to a struct instance B. I will need to do some processing on this data by calling the parent.
struct A {
val : u8
}
struct B {
data : u8,
a : A
}
impl A {
pub fn process(&mut self, b : &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
}
impl B {
pub fn process(&mut self) {
self.a.process(self);
}
}
fn main() {
let mut b = B {
data : 0,
a : A {
val : 3
}
};
b.process();
}
When I try to call b.process(), I'm getting the following failure:
error[E0499]: cannot borrow `self.a` as mutable more than once at a time
--> src/main.rs:47:9
|
47 | self.a.process(self);
| ^^^^^^^-------^----^
| | | |
| | | first mutable borrow occurs here
| | first borrow later used by call
| second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:47:24
|
47 | self.a.process(self);
| ---------------^^^^-
| | | |
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
All of this works fine when mutable references aren't needed.
So my question is, what's the right way to do this when I need this type of relationship between the two structs?
In Rust you can either have a single mutable reference or multiple immutable references, or, put differently: single writer / multiple readers.
let mut a = 0; // Only mutable variables can be written to
let a1 = &a;
let a2 = &a; // Readers can be many
// This is an error:
let a3 = &mut a; // You cannot write to `a` while it is borrowed for reading
print!("{} {} {}", a1, a2, a3)
let mut a = 0;
let a1 = &mut a; // You can have a single writer
// This is an error:
let a2 = &mut a; // But there can be only one
// This is also an error:
let a3 = &a; // You cannot read while `a` can be written to
print!("{} {} {}", a1, a2, a3)
Following this logic we can make some observations on the code
impl A {
// this implies that both self and B can change
pub fn process(&mut self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
pub fn process_changes_a(&mut self, b: &B) {
println!("Processing {} - {}", b.data, self.val);
}
pub fn process_changes_b(&self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
}
}
impl B {
pub fn process(&mut self) {
// it's possible to use clones to work around this
// however it's probably better to refactor the logic
// let's see what happens when using clones
let mut tmp_self = self.clone();
let mut tmp_a = self.a.clone();
// this can modify both self.a and tmp_self
self.a.process(&mut tmp_self);
// now self and tmp_self could be different
// does self need to have the value of the &mut B?
// note: this clone is only necessary for
// the other examples to compile
*self = tmp_self.clone();
// or does only self.a need to change?
tmp_a.process(self);
self.a = tmp_a;
// or should the original self.a stay the same?
self.data = tmp_self.data;
}
pub fn process_changes_a(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_a could
// modify a through self while reading b.a
let mut tmp_a = self.a.clone();
tmp_a.process_changes_a(self);
self.a = tmp_a;
}
pub fn process_changes_b(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_b could
// modify a through b.a while reading self
let tmp_a = self.a.clone();
tmp_a.process_changes_b(self);
}
pub fn process_on_self(&mut self) {
// if you need to modify both self and self.a
// it might be best to have the method directly on B
println!("Processing {} - {}", self.data, self.a.val);
}
}
The problem really comes from the fact that A::process(&mut self, b: &mut B) doesn't know that both self and b.a reference the same value when called from B and expects them to be different. You can make it work by using clones or copies, however it is probably unnecessary.
Personally, I'd probably try to move the logic of process() entirely to B. In your example A depends on B, but also B depends on A. This would make it so that only B depends on A, which makes things simpler.
You can't that's against Rusts aliasing rules, you'd have two mutable references to the A one direct and one indirectly through B. If you really wanted to you could use interior mutability (RefCell, Mutex, ...) but as kaya3 pointed out your suggested implementation seems rather strange even from an OO viewpoint. If it needs a B anyways, I'd just implement it on B diretly without the indirection.

How to dissociate mutability from lifetime in Rust?

I want to have two types (in my question-fitted examples I will mark them as IdHandler counting IDs, and IdUser using the IDs), where the dependent one of them should not outlive (hence, lifetimes) the dependency, and that's the only requirement. Figured the quickest solution would be using PhantomData<&'...>:
struct IdHandler {
id_counter: u64,
}
struct IdUser<'a> {
_a: PhantomData<&'a IdHandler>,
id: u64,
}
Then, using a mutable reference with a specified lifetime, I made a function in impl IdHandler to create the users:
fn new_id_user<'a>(self: &'a mut IdHandler) -> IdUser<'a> {
let res = IdUser {
_a: PhantomData,
id: self.id_counter,
};
self.id_counter += 1;
res
}
Now, I will make a function that takes in a mutable reference and tries to make a pair of IdUsers:
fn f<'a>(id_handler: &'a mut IdHandler) -> (IdUser<'a>, IdUser<'a>) {
let a1 = id_handler.new_id_user();
let a2 = id_handler.new_id_user();
(a1, a2)
}
And here's an example of how those types and functions may be used:
fn main() {
let mut id_handler = IdHandler { id_counter: 0u64 };
let (a1, a2) = f(&mut id_handler);
assert_eq!(a1.id, 0u64);
assert_eq!(a2.id, 1u64);
assert_eq!(id_handler.id_counter, 2u64);
id_handler.stop(); // fn stop(self) {}
// Ideally here 'a is dead,
// so you can't perform operations on IdUser<'a>
// assert_eq!(a2.id, 1u64);
}
Given the fact that new_id_user(...) only uses the mutability for a moment, and then hopefully "releases" it back (as it is not used any longer than the function call - I do not know the exact rule Rust uses, but it works without _a/'a or when fn f(...) -> ()), I'd expect f(...) to work just fine. However, the compiler has greeted me with following:
error[E0499]: cannot borrow `*id_handler` as mutable more than once at a time
--> src\main.rs:29:14
|
27 | fn f<'a>(id_handler: &'a mut IdHandler) -> (IdUser<'a>, IdUser<'a>) {
| -- lifetime `'a` defined here
28 | let a1 = id_handler.new_id_user();
| ------------------------ first mutable borrow occurs here
29 | let a2 = id_handler.new_id_user();
| ^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
30 | (a1, a2)
| -------- returning this value requires that `*id_handler` is borrowed for `'a`
Does anyone know whether there is a solution that I'm missing, or am I doomed to allow IdUsers to outlive the IdHandler?
Unfortunately you cannot. Preserving a value with a lifetime will prevent the mutating the value from which it was derived even if you don't actually keep a reference to it. A common workaround if you want to ensure the lifetimes are bound while still being able to mutate is to use interior mutability (via Cell, RefCell, Mutex, etc).
Here's a working example using Cell:
use std::marker::PhantomData;
use std::cell::Cell;
struct IdHandler {
id_counter: Cell<u64>,
}
impl IdHandler {
fn new_id_user<'a>(self: &'a IdHandler) -> IdUser<'a> {
let res = IdUser {
_a: PhantomData,
id: self.id_counter.get(),
};
self.id_counter.set(self.id_counter.get() + 1);
res
}
}
struct IdUser<'a> {
_a: PhantomData<&'a IdHandler>,
id: u64,
}
fn f<'a>(id_handler: &'a IdHandler) -> (IdUser<'a>, IdUser<'a>) {
let a1 = id_handler.new_id_user();
let a2 = id_handler.new_id_user();
(a1, a2)
}
fn main() {
let mut id_handler = IdHandler { id_counter: Cell::new(0u64) };
let (a1, a2) = f(&mut id_handler);
assert_eq!(a1.id, 0u64);
assert_eq!(a2.id, 1u64);
}

Returning a reference to a captured mutable variable

So I have a function which looks like this
fn foo() {
let items = vec![0.2, 1.5, 0.22, 0.8, 0.7, 2.1];
let mut groups: HashMap<u32, String> = HashMap::new();
let mut group = |idx: f32| -> &mut String {
let rounded = (idx / 0.2).floor() as u32;
groups
.entry(rounded)
.or_insert_with(|| format!("{}:", rounded))
};
for item in items.iter() {
group(*item).push_str(&format!(" {}", item))
}
}
and this code does not compile, with the following error:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:9:9
|
5 | let mut groups: HashMap<u32, String> = HashMap::new();
| ---------- variable defined here
6 |
7 | let mut group = |idx: f32| -> &mut String {
| - inferred to be a `FnMut` closure
8 | let rounded = (idx / 0.2).floor() as u32;
9 | groups
| ^-----
| |
| _________variable captured here
| |
10 | | .entry(rounded)
11 | | .or_insert_with(|| format!("{}:", rounded))
| |_______________________________________________________^ returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
Edit
As #Sven Marnach pointed out, the problem here is that I could create 2 mutable references to the same object:
fn foo() {
// ...
let ok = groups(0.1);
let problem = groups(0.1);
}
Original (incorrect)
I think that Rust is telling me, the closure group is mutably capturing the variable groups and then returning a reference to an object owned by groups. So the danger here is that the following code would return a dangling pointer (since groups is dropped when it goes out of scope after foo finishes).
fn foo() -> &String {
/* ... */ return groups(0.1); }
So is there any way to return a reference from a captured mutable HashMap like this?
I think that Rust is telling me, the closure group is mutably capturing the variable groups and then returning a reference to an object owned by groups. So the danger here is that if I were to write:
then I would be returning a dangling pointer (since groups is dropped when it goes out of scope after foo finishes).
No. If that were the case Rust could (and would) warn about that.
The problem is that the lifetimes around function traits are problematic, because they don't have a way to match the lifetime of the result to the lifetime of the function itself.
As a result, rust blanket bans returning any reference to captured data from a closure.
As far as I can tell the solutions are:
don't use a closure, instead pass in groups as an argument into the function (anonymous or named)
use some sort of shared ownership and interior mutability e.g. have the map store and return Rc<RefCell<String>>
desugar the closure to a structure with a method, that way the lifetimes become manageable:
use std::collections::HashMap;
struct F<'a>(&'a mut HashMap<u32, String>);
impl F<'_> {
fn call(&mut self, idx: f32) -> &mut String {
let rounded = (idx / 0.2).floor() as u32;
self.0
.entry(rounded)
.or_insert_with(|| format!("{}:", rounded))
}
}
pub fn foo() {
let items = vec![0.2, 1.5, 0.22, 0.8, 0.7, 2.1];
let mut groups: HashMap<u32, String> = HashMap::new();
let mut group = F(&mut groups);
for item in items.iter() {
group.call(*item).push_str(&format!(" {}", item))
}
}
Note that the above stores a reference to match the original closure, but in reality I see no reason not to move the hashmap into the wrapper entirely (and the struct can init itself fully without the need for a two-step initialisation as well):
use std::collections::HashMap;
struct F(HashMap<u32, String>);
impl F {
fn new() -> Self { Self(HashMap::new()) }
fn call(&mut self, idx: f32) -> &mut String {
let rounded = (idx / 0.2).floor() as u32;
self.0
.entry(rounded)
.or_insert_with(|| format!("{}:", rounded))
}
}
pub fn foo() {
let items = vec![0.2, 1.5, 0.22, 0.8, 0.7, 2.1];
let mut group = F::new();
for item in items.iter() {
group.call(*item).push_str(&format!(" {}", item))
}
}

rust initializing a String field in a struct with a String that belongs to a HashMap in the same structure [duplicate]

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 1 year ago.
I have read those two similar questions here and here. But still can't figure out how to achieve what I want: initializing a String field in a struct with a String that belongs to a HashMap in the same structure. Here is my initial code:
use std::collections::HashMap;
struct S<'a> {
a: HashMap<String,Vec<String>>,
b: &'a String,
}
impl <'a> S<'a> {
fn new() -> S<'a> {
let mut v:Vec<String> = Vec::new();
v.push("a".to_string());
v.push("b".to_string());
let mut h = HashMap::new();
h.insert("toto".to_string(),v);
let b = &h.get("toto").unwrap()[0];
S {
a: h, // error[E0505]: cannot move out of `h` because it is borrowed
b: b // error[E0515]: cannot return value referencing local variable `h`
}
}
}
fn main() {
let mut s = S::new();
println!("s.b = {}", s.b);
}
I would like b to be initilaized with a String value that belong to the HashMap a. Since the above did not work, I tried to initialize b with an empty String, and immediatly change b's value after creating s:
use std::collections::HashMap;
struct S {
a: HashMap<String,Vec<String>>,
b: String,
}
impl S {
fn new() -> S {
let mut v:Vec<String> = Vec::new();
v.push("a".to_string());
v.push("b".to_string());
let mut h = HashMap::new();
h.insert("toto".to_string(),v);
let b = "".to_string();
S {
a: h,
b: b
}
}
}
fn main() {
let mut s = S::new();
s.b = s.a.get("toto").unwrap()[0]; //error[E0507]: cannot move out of index of `Vec<String>`
println!("s.b = {}", s.b);
}
Since I cannot copy the value into s.b:
error[E0507]: cannot move out of index of `Vec<String>`
--> src/main.rs:24:15
|
24 | s.b = s.a.get("toto").unwrap()[0]; //error[E0507]: cannot move out of index of `Vec<String>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
I thought that a reference could work:
use std::collections::HashMap;
struct S<'a> {
a: HashMap<String,Vec<String>>,
b: &'a String,
}
impl <'a> S<'a> {
fn new() -> S<'a> {
let mut v:Vec<String> = Vec::new();
v.push("a".to_string());
v.push("b".to_string());
let mut h = HashMap::new();
h.insert("toto".to_string(),v);
let b = &"".to_string();
S {
a: h,
b: b // error[E0515]: cannot return value referencing temporary value
}
}
}
fn main() {
let mut s = S::new();
s.b = &s.a.get("toto").unwrap()[0];
println!("s.b = {}", s.b);
}
But of course, I run into the same issue of referencing a value that does not have a lifetime longer than the function. No clue how/if I can tell the compiler that my empty String should live as long as S.
There might be an obvious solution, but if so, I can't see it :-(
There might be an obvious solution, but if so, I can't see it :-(
If your goal is to share the value between the map and the field, then no. Rust does not like self-referential data structures.
And a string is affine, you can't have both the structure and the nested map own the "same" string unless:
you relax the ownership using Rc or Arc
you clone() the string and both just have a copy of the same thing
There are also crates for string caching / interning, but I've no idea how convenient & efficient they are.

Returning a mutable reference that is behind an immutable reference, passed to the function

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;
}

Resources