Structs containing mutable slices [duplicate] - reference

This question already has answers here:
How to get mutable references to two array elements at the same time?
(8 answers)
Closed 4 years ago.
I'm trying to understand lifetimes and storing mutable slices inside a struct.
I came up with this example with a struct with a slice and a take function that will return n elements (if present) and store the rest in the structure itself. This code does not compile.
fn main() {
let mut v: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut blah = Blah { slice: &mut v[..] };
let b = blah.take(5);
println!("b: {:?}", b);
}
#[derive(Debug)]
struct Blah<'a> {
slice: &'a mut [u8],
}
impl<'a> Blah<'a> {
pub fn take(&'a mut self, n: usize) -> Option<Self> {
if self.slice.len() > n {
let blah = Blah {
slice: &mut self.slice[..n],
};
self.slice = &mut self.slice[n..];
Some(blah)
} else {
None
}
}
}
Compiler error:
error[E0499]: cannot borrow `*self.slice` as mutable more than once at a time
--> src/main.rs:21:31
|
15 | impl<'a> Blah<'a> {
| -- lifetime `'a` defined here
...
19 | slice: &mut self.slice[..n],
| ---------- first mutable borrow occurs here
20 | };
21 | self.slice = &mut self.slice[n..];
| ^^^^^^^^^^ second mutable borrow occurs here
22 | Some(blah)
| ---------- returning this value requires that `*self.slice` is borrowed for `'a`
I have a large in-memory buffer that I don't want to copy. Instead, I want to keep referring to the same memory by carrying around "fat pointers" (something like offset + length).

The Rust compiler isn't able to detect that the two borrows of sub-slices are non-overlapping. When you borrow &mut self.slice[..n], the whole of self.slice is considered to be borrowed, so you can't then borrow the remaining elements.
There is a method split_at_mut, designed to solve this problem by producing two disjoint mutable borrows from a slice. Your code can be updated to use it like this:
impl<'a> Blah<'a> {
pub fn take(&'a mut self, n: usize) -> Option<Self> {
if self.slice.len() > n {
let (left, right) = self.slice.split_at_mut(n);
let blah = Blah {
slice: left
};
self.slice = right;
Some(blah)
} else {
None
}
}
}

Related

Cannot borrow `x` as mutable more than once at a time?

Logically this code is correct, However rust doesn't understand the context. Trying to reading some byte from cursor with very short 'lifetime of exclusive reference.
Why this code does not compile? Playground
struct Cursor {
offset: usize,
data: [u8; 4],
}
impl Cursor {
fn read_slice(&mut self, n: usize) -> &[u8] {
let data = &self.data[self.offset..self.offset + n];
self.offset += n;
data
}
}
struct FooBar<'a> {
foo: &'a [u8],
bar: &'a [u8],
}
fn read_foobar_from<'a>(cursor: &'a mut Cursor) -> FooBar<'a> {
FooBar {
foo: cursor.read_slice(2),
bar: cursor.read_slice(2),
}
}
Error:
error[E0499]: cannot borrow `*cursor` as mutable more than once at a time
--> src/main.rs:22:14
|
19 | fn read_foobar_from<'a>(cursor: &'a mut Cursor) -> FooBar<'a> {
| -- lifetime `'a` defined here
20 | / FooBar {
21 | | foo: cursor.read_slice(2),
| | -------------------- first mutable borrow occurs here
22 | | bar: cursor.read_slice(2),
| | ^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
23 | | }
| |_____- returning this value requires that `*cursor` is borrowed for `'a`
The duplicate I linked as a comment addresses why you get this error. (tl;dr: Rust doesn't downgrade borrows; a function borrowing a value mutably and returning an immutable reference with the same lifetime causes the mutable borrow to exist as long as the returned reference does.)
How might we solve the problem in this case?
When I think "cursor" I don't think "something that owns data and allows reading that data out," I think "something that reads out data owned by something else." It turns out that model can solve this problem by having something else to tie the lifetime of the returned reference to.
If we make Cursor borrow the data instead of owning it, we can denote that the returned reference is bound to the lifetime of that data instead of the mutable borrow of self:
struct Cursor<'a> {
offset: usize,
data: &'a [u8],
}
impl<'a> Cursor<'a> {
fn read_slice(&mut self, n: usize) -> &'a [u8] {
let data = &self.data[self.offset..self.offset + n];
self.offset += n;
data
}
}
(Playground)
If you want Cursor to own the data then interior mutability (e.g. offset: Cell<usize>) may be your only option:
struct Cursor {
offset: Cell<usize>,
data: [u8; 4],
}
impl Cursor {
fn read_slice(&self, n: usize) -> &[u8] {
let offset = self.offset.get();
let data = &self.data[offset..offset + n];
self.offset.set(offset + n);
data
}
}
(Playground)

How to rereference a mutable slice [duplicate]

This question already has answers here:
Can I reassign a mutable slice reference to a sub-slice of itself?
(2 answers)
Closed 2 years ago.
I want to uptade a slice through a mutable reference.
While this does work with immutable slices:
fn shrink(value: &mut &[u8]) {
*value = &value[0..2];
}
fn main() {
let a = [0; 4];
let mut a_slice: &[u8] = &a;
shrink(&mut a_slice);
println!("{:?}", a_slice);
}
It doesn't work with mutable ones:
fn shrink<'a: 'b, 'b>(value: &'a mut &'b mut [u8]) {
*value = &mut value[0..2];
}
fn main() {
let mut a = [0; 4];
let mut a_slice: &mut [u8] = &mut a;
shrink(&mut a_slice);
println!("{:?}", a_slice);
}
Error message:
error[E0502]: cannot borrow `a_slice` as immutable because it is also borrowed as mutable
--> src/main.rs:8:22
|
7 | shrink(&mut a_slice);
| ------------ mutable borrow occurs here
8 | println!("{:?}", a_slice);
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
I know that there is a way to update the slice by directly returning a subslice.
But is there a way to make rereferencing a mutable slice through mutable reference possible?
The problem is similar to this one, but I can't figure what makes it so different, that proposed solution doesn't work.
I don't know what the problem is with that code, but one option would be to return the updated slice directly:
fn shrink(value: &mut [u8]) -> &mut [u8] {
&mut value[0..2]
}
fn main() {
let mut a = [0; 4];
let mut a_slice = &mut a[..];
a_slice = shrink(a_slice);
println!("{:?}", a_slice);
}
Rather than updating via the mutable reference, updating in the caller makes it clear that the old value of a_slice won't be used any more.

Why does an Iterator trait object referring to a sibling field fail to compile when the concrete type works?

I'd like to have an iterator that points into a Vec of the same struct.
The following works fine (playground):
struct Holder1<'a> {
vec: Vec<i32>,
iterator: Option<Box<std::slice::Iter<'a, i32>>>,
}
fn holder1_test() {
let vec = vec![1, 2, 3, 4];
let mut holder = Holder1 {
vec,
iterator: None,
};
let iterator: Box<std::slice::Iter<'_, i32>> = Box::new(holder.vec.iter());
holder.iterator = Some(iterator);
for iter_elem in holder.iterator.as_mut().unwrap() {
println!("iter: {}", iter_elem);
}
}
(I know the Box isn't needed here, I just wanted to keep this as close as possible to the next code snippet.)
I'd like to use a trait object, dyn Iterator, instead of the concrete type. I've slightly modified the example from above for that (playground):
struct Holder2<'a> {
vec: Vec<i32>,
iterator: Option<Box<dyn Iterator<Item = &'a i32>>>,
}
fn holder2_test() {
let vec = vec![1, 2, 3, 4];
let mut holder = Holder2 {
vec,
iterator: None,
};
let iterator: Box<dyn Iterator<Item = &'_ i32>> = Box::new(holder.vec.iter());
holder.iterator = Some(iterator);
for iter_elem in holder.iterator.as_mut().unwrap() {
println!("iter: {}", iter_elem);
}
}
This fails to compile:
error[E0597]: `holder.vec` does not live long enough
--> src/lib.rs:12:64
|
12 | let iterator: Box<dyn Iterator<Item = &'_ i32>> = Box::new(holder.vec.iter());
| ^^^^^^^^^^ borrowed value does not live long enough
...
18 | }
| -
| |
| `holder.vec` dropped here while still borrowed
| borrow might be used here, when `holder` is dropped and runs the destructor for type `Holder2<'_>`
What makes the second example so different to the first example that causes the compilation failure? Both iterators point to an element in the Vec of the same struct - so what's the conceptual difference here? Is there a way to get this to work with trait objects?
I'm aware that using an index instead of an iterator would solve this, but I'm rather interested in the underlying reasons of why this doesn't work.

cannot borrow `self` as immutable because `self.chars` is also borrowed as mutable [duplicate]

This question already has answers here:
Mutably borrow one struct field while borrowing another in a closure
(2 answers)
Closed 5 years ago.
I need immutable access to one struct field and mutable access to another one, but they have to be stacked on each other. I've had this problem multiple times and I don't know how to fix this.
use std::collections::HashMap;
struct Bar;
impl Bar {
fn get(&self) -> i32 {
100
}
}
struct Foo {
chars: HashMap<char, i32>,
b: Bar,
}
impl Foo {
fn run(&mut self) {
self.chars.entry('c').or_insert_with(|| self.b.get() * 100);
}
}
fn main() {
let mut m = Foo {
chars: HashMap::new(),
b: Bar,
};
m.run();
}
error[E0502]: cannot borrow `self` as immutable because `self.chars` is also borrowed as mutable
--> src/main.rs:16:46
|
16 | self.chars.entry('c').or_insert_with(|| self.b.get() * 100);
| ---------- ^^ ---- - mutable borrow ends here
| | | |
| | | borrow occurs due to use of `self` in closure
| | immutable borrow occurs here
| mutable borrow occurs here
The problem is that you're trying to borrow self mutably and immutably, as the compiler says. As pointed out by Stefan, the borrow checker can't distinguish access to fields across closure boundaries, so we need to help it a bit by being more explicit about what we want to borrow and pass to the closure.
A way to do this is to take out a reference to self.b and use that inside the or_insert_with():
use std::collections::HashMap;
struct Bar;
impl Bar {
fn get(&self) -> i32 {
100
}
}
struct Foo {
chars: HashMap<char, i32>,
b: Bar,
}
impl Foo {
fn run(&mut self) {
let b = &self.b;
self.chars.entry('c').or_insert_with(|| b.get() * 100);
}
}
fn main() {
let mut m = Foo {
chars: HashMap::new(),
b: Bar,
};
m.run();
}

Why doesn't the lifetime of a mutable borrow end when the function call is complete?

I'm writing a bot for halite.io, and am having issues understanding some of the effects of borrowing. Here is the code that will not compile:
let scanLoc = hlt::types::Location {
x: oflow(coord.0 + l.x as i32, game_map.width),
y: oflow(coord.1 + l.y as i32, game_map.width),
};
let scan = game_map.get_site(scanLoc, types::STILL);
if (&scan.owner != id) | (scan.owner != 0u8) {
let ang = game_map.get_angle(l, scanLoc);
debug!("angle b/w: {}", ang);
return (l, 2);
}
This is the compiler error:
error[E0502]: cannot borrow `*game_map` as immutable because it is also borrowed as mutable
--> src/MyBot.rs:112:27
|
110 | let scan = game_map.get_site(scanLoc, types::STILL);
| -------- mutable borrow occurs here
111 | if (&scan.owner != id) | (scan.owner != 0u8) {
112 | let ang = game_map.get_angle(l, scanLoc);
| ^^^^^^^^ immutable borrow occurs here
...
116 | }
| - mutable borrow ends here
This is the code for the GameMap functions and struct:
#[derive(Clone, Debug)]
pub struct GameMap {
pub width: u16, // Number of columns.
pub height: u16, // Number of rows.
pub contents: Vec<Vec<Site>>,
}
impl GameMap {
pub fn in_bounds(&self, l: Location) -> bool {
// ...
}
pub fn get_distance(&self, l1: Location, l2: Location) -> u16 {
// ...
}
pub fn get_angle(&self, l1: Location, l2: Location) -> f64 {
// ...
}
pub fn get_location(&self, l: Location, d: u8) -> Location {
// ...
}
pub fn get_site(&mut self, l: Location, d: u8) -> &mut Site {
// ...
}
}
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Editor's note: This specific problem has been solved by the introduction of non-lexical lifetimes.
Let's look at a tiny reproduction:
struct Site {
owner: u8,
}
struct GameMap {
site: Site,
}
impl GameMap {
fn do_anything(&self) {}
fn get_site(&mut self) -> &mut Site {
&mut self.site
}
}
fn main() {
let mut game_map = GameMap {
site: Site { owner: 0 },
};
let site = game_map.get_site();
game_map.do_anything();
}
error[E0502]: cannot borrow `game_map` as immutable because it is also borrowed as mutable
--> src/main.rs:22:5
|
21 | let site = game_map.get_site();
| -------- mutable borrow occurs here
22 | game_map.do_anything(); // Compiler error!
| ^^^^^^^^ immutable borrow occurs here
23 | }
| - mutable borrow ends here
Our GameMap only owns a single Site, but that's enough. The call to get_site returns a reference (in this case it happens to be mutable):
fn get_site(&mut self) -> &mut Site
Thanks to lifetime elision, this is the same as
fn get_site<'a>(&'a mut self) -> &'a mut Site
This means that the returned reference is allowed to point to something inside of GameMap (which it does). Then we keep that reference in a variable - site!
That means that we can no longer use any immutable references to game_map as they might have been (or will in the future be) invalidated by the changes that can be made to the map through the mutable reference:
At any given time, you can have either one mutable reference or any number of immutable references.
References must always be valid.
— The Rust Programming Language chapter on references and borrowing
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Rust borrows your struct mutably because you are calling a method that requires a mutable reference (&mut self). That method then returns a mutable reference, transferring the borrow of the struct to the returned value. The borrow ends when the returned value goes out of scope.
So, how do you fix it? Probably the most flexible solution is to introduce a scope to constrain the mutable borrow:
let zhu_li_do_the_thing = {
let site = game_map.get_site();
site.owner == 5 || site.owner == 42
};
if zhu_li_do_the_thing {
game_map.do_anything();
}
Another is the same idea, but requires that you never store the borrow in a variable at all. Thus the mutable borrow doesn't last beyond that statement:
if game_map.get_site().owner == 42 {
game_map.do_anything();
}
It's common for idiomatic Rust code to have foo and foo_mut variants of a method, for when you don't need mutability. This may not help if you need to mutate game_map while the immutable borrow of site is still outstanding.
fn get_site(&self) -> &Site {
&self.site
}
fn get_site_mut(&mut self) -> &mut Site {
&mut self.site
}
let site = game_map.get_site();
if site.owner == 5 || site.owner == 42 {
game_map.do_anything();
}
See also:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
What are non-lexical lifetimes?

Resources