I'm new to rust and try to understand &mut ref variables and mutability. I started creating a simple link list with pop_back function.
pub fn pop_back(&mut self) -> Option<T> {
let mut head = &mut self.head;
while let Some(v) = head {
if v.next.is_none() {
break;
}
head = &mut v.next;
}
head.take().map(|node| node.data)
}
but can't make it to work. error is cannot borrow *head as mutable more than once at a time.
How can I tell rust that I want to only change the reference in my loop not the value?
I don't want to add another tail variable to my list so without changing structure how can I make this work?
this is the struct definition
pub struct Node<T> {
data: T,
next: Option<Box<Node<T>>>
}
pub struct SimpleLinkedList<T> {
head: Option<Box<Node<T>>>,
}
This is a known limitation of the borrow checker. The next-gen Polonius will solve this.
In the meantime, the solution (without unsafe) is to repeat the calculation. In your case, this means some unwrap()s:
pub fn pop_back(&mut self) -> Option<T> {
let mut head = &mut self.head;
while head.is_some() {
if head.as_mut().unwrap().next.is_none() {
break;
}
head = &mut head.as_mut().unwrap().next;
}
head.take().map(|node| node.data)
}
See also:
Cannot borrow as mutable in loop
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
Related
Stripped down to the bare essentials, my problematic code looks as follows:
pub struct Item;
impl Item {
/// Partial copy. Not the same as simple assignment.
pub fn copy_from(&mut self, _other: &Item) {
}
}
pub struct Container {
items: Vec<Item>,
}
impl Container {
pub fn copy_from(&mut self, self_idx: usize, other: &Container, other_idx: usize) {
self.items[self_idx].copy_from(&other.items[other_idx]);
}
}
fn main() {
let mut container = Container { items: vec![Item, Item] };
container.copy_from(0, &container, 1);
}
This is of course rejected by the borrow checker:
error[E0502]: cannot borrow `container` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
21 | container.copy_from(0, &container, 1);
| ^^^^^^^^^^---------^^^^----------^^^^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
I understand why that happens, but I don't have a good solution.
I've considered adding a dedicated copy_from_self function that callers need to use in cases where self == other:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
if to_idx != from_idx {
unsafe {
let from_item: *const Item = &self.items[from_idx];
self.items[to_idx].copy_from(&*from_item);
}
}
}
But this is un-ergonomic, bloats the API surface, and needs unsafe code inside.
Note that in reality, the internal items data structure is not a simple Vec, so any approach specific to Vec or slice will not work.
Is there an elegant, idiomatic solution to this problem?
If I understand the comments on the question correctly, a general solution seems to be impossible, so this answer is necessarily specific to my actual situation.
As mentioned, the actual data structure is not a Vec. If it were a Vec, we could use split_at_mut to at least implement copy_from_self safely.
But as it happens, my actual data structure is backed by a Vec, so I was able to add a helper function:
/// Returns a pair of mutable references to different items. Useful if you need to pass
/// a reference to one item to a function that takes `&mut self` on another item.
/// Panics if `a == b`.
fn get_mut_2(&mut self, a: usize, b: usize) -> (&mut T, &mut T) {
assert!(a != b);
if a < b {
let (first, second) = self.items.split_at_mut(b);
(&mut first[a], &mut second[0])
} else if a > b {
let (first, second) = self.items.split_at_mut(a);
(&mut second[0], &mut first[b])
} else {
panic!("cannot call get_mut_2 with the same index {} == {}", a, b);
}
}
Now we can implement copy_from_self without unsafe code:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
let (to, from) = self.items.get_mut_2(to_idx, from_idx);
to.unwrap().copy_from(from.unwrap());
}
I have a situation where I have to move a struct from one object to another through a &mut self. Take a look:
pub struct MyStruct {
//no copy trait
device: Device
}
impl MyStruct {
pub fn finalize(&mut self) {
//error: cannot move since I borrowed
let interface = InterfaceBuilder::new(self.device)
}
}
First of all, why I cannot move something out of a borrowed mutable reference? Borrowed mutables are exclusive, there's no chance another code is looking into it.
Well, to address this problem I changed to
pub struct MyStruct {
//no copy trait
device: RefCell<Device>
}
impl MyStruct {
pub fn finalize(&mut self) {
//error on `self.device`: cannot move out of `self.device` which is behind a mutable reference
let interface = InterfaceBuilder::new(self.device.into_inner())
}
}
I know why the error occurs:
pub fn into_inner(self) -> T
calling into_inner makes self.device move. Why RefCell simply does not have an implementation pub fn into_inner(&mut self) -> T? I don't see a problem.
You cannot move out of a mutable reference because that would leave the original object incomplete.
Consider this code:
struct MyStruct {
s: String
}
fn finalize(f: &mut MyStruct) {
let _x = f.s; //error E0507!
}
fn main() {
let mut my = MyStruct {
s: "hi".into()
};
finalize(&mut my);
println!("{}", my.s); //what should this do?
}
Then, RefCell::into_inner(&mut self) -> T has the same problem. You could call it twice in a row and you would get two T values where before there was only one. And that, for a non Copy type is impossible.
If you want this function to consume the inner value, probably it should consume the outer value too:
fn finalize(f: MyStruct) {
let _x = f.s;
}
If you really want to move a value out of a mutable reference, you must leave something valid in its place. The easiest way is to declare an Option and use take() to steal and replace it with a None:
struct MyStruct {
s: Option<String>
}
fn finalize(f: &mut MyStruct) {
let _x = f.s.take();
}
Naturally, Option::take returns an Option so that if you call it twice, the second time you get None. If you are positive you have a value you can do take().uwnrap().
Alternatively, if your field type is Default you can use std::mem::take that replaces it with a default-created value:
struct MyStruct {
s: Vec<i32>
}
fn finalize(f: &mut MyStruct) {
let _x = std::mem::take(&mut f.s);
}
PS #1: there is Cell::take(&self) -> T, but only if T implements Default. It works just like std::mem::take but with a non-mutable reference.
PS #2: there is also unsafe fn ManuallyDrop::take(slot: &mut ManuallyDrop<T>) -> T, that is intented to be used in advanced drop implementations. But it is unsafe so it should never be your first option: if you call it twice you will get undefined behavior.
I am trying to do the Simple Linked List Exercism problem, but I am stuck implementing the pop() method. The errors I get are not very clear to me; I'm not quite used to Rust's way of thinking, I guess.
Also, because of the compiler suggestions, I added a bunch of as_ref() that I don't really understand.
I am interested in knowing why my way of doing things doesn't work more than the solution.
pub struct SimpleLinkedList<T> {
head: Option<Box<Node<T>>>,
}
struct Node<T> {
data: T,
next: Option<Box<Node<T>>>,
}
impl<T> SimpleLinkedList<T> {
pub fn new() -> Self {
unimplemented!()
}
pub fn len(&self) -> usize {
unimplemented!()
}
pub fn push(&mut self, _element: T) {
unimplemented!()
}
pub fn pop(&mut self) -> Option<T> {
// Recursive function to return the before last element of the list
fn get_before_last<'a, T>(
prev: &'a Box<Node<T>>,
current: &'a Box<Node<T>>,
) -> &'a Box<Node<T>> {
match ¤t.next {
Some(next_node) => get_before_last(¤t, &next_node),
None => &prev,
}
}
// Check if the head is None
match &self.head {
None => return None,
_ => (),
};
let before_last = &mut match &self.head {
// Beginning of the recursion
Some(node) => get_before_last(&node, node.next.as_ref().unwrap()),
None => self.head.as_ref().unwrap(),
};
let to_pop = before_last.next.as_ref();
before_last.next = None;
Some(to_pop.unwrap().data)
}
}
I get the following errors:
error[E0594]: cannot assign to `before_last.next` which is behind a `&` reference
--> src/lib.rs:48:9
|
48 | before_last.next = None;
| ^^^^^^^^^^^^^^^^ cannot assign
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:50:14
|
50 | Some(to_pop.unwrap().data)
| ^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
In your code, before_last is not mutable. In fact it's a &mut &'a Box<Node>. For this reason you cannot assign anything to the node because it's a mutable reference to an immutable one.
The best suggestion I can give you is to rethink the implementation. Instead of pushing and popping to the end of the chain, you can do so on the front.
Create a new boxed node, remove the head and put it in the new node's next field. Then the new node becomes the head.
This way you have a LIFO list and you don't have to traverse the whole list to push & pop, so it's also more efficient. Pushing to the front also reduces the amount of code required.
My solution is available on Exercism.
Multiple questions were already asked regarding this topic:
Returning iterator of a Vec in a RefCell
How do I return an iterator that has a reference to something inside a RefCell?
How can I return an iterator over a locked struct member in Rust?
The answers are more or less: It's not possible (without unsafe).
I tried the unsafe variant myself and want to ask if this way is safe.
The idea is that I wrap the guard in a struct that implements Iterator. Besides the guard, an iterator is stored which will be created from the stored guard:
struct MapIter<'a> {
guard: RwLockReadGuard<'a, HashMap<i32, i32>>,
iter: Iter<'a, i32, i32>,
}
It's created with these lines:
impl<'a> MapIter<'a> {
fn new(map: &'a RwLock<HashMap<i32, i32>>) -> Box<Self> {
// create a `box Self`
// the iterator remains uninitialized.
let mut boxed = Box::new(Self {
guard: map.read().expect("ToDo"),
iter: unsafe { mem::uninitialized() },
});
// create the iterator from `box Self`.
boxed.iter = unsafe {
(*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter()
};
boxed
}
}
Now it can implement Iterator:
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a i32, &'a i32);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
Is this code safe?
See this code in action at the playground.
Additionally I get a trivial cast warning
warning: trivial cast: warning: trivial cast: `&std::sync::RwLockReadGuard<'_, std::collections::HashMap<i32, i32>>` as `*const std::sync::RwLockReadGuard<'a, std::collections::HashMap<i32, i32>>`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
|
| unsafe { (*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
How to get around this?
No, it's not safe. I can use Container to create a dangling reference in safe code:
let container = Container::new(); // create a container
let r = {
let mut it = container.iter();
it.next() // obtain a reference to part of it
};
container.map.write().unwrap().clear(); // empty the container
println!("{:?}", r); // oh dear.
In the playground this compiles, which isn't good, because r contains references to data that are invalidated when the HashMap is cleared.
Vladimir Matveev's answer to a similar question explains in more detail why this is unsound, and contains the following concise summary:
You cannot do this because it would allow you to circumvent runtime checks for uniqueness violations.
I am trying to have a value in a trait that can be mutated by means of a reference. The problem is that the String values are very large and may be accessed by many threads, so my solution looks something like this:
trait MyTrait {
fn name<'a>(&'a mut self) -> &'a mut String;
}
struct SimpleImpl {
name: String
}
impl MyTrait for SimpleImpl {
fn name<'a>(&'a mut self) -> &'a mut String {
&mut self.name
}
}
use std::sync::{Arc,RwLock};
struct ParallelImpl {
name: Arc<RwLock<String>>
}
impl MyTrait for ParallelImpl {
fn name<'a>(&'a mut self) -> &'a mut String {
self.name.get_mut().unwrap()
}
}
fn main() {
let mut a = SimpleImpl { name: String::from("simple") };
let mut b = ParallelImpl { name: Arc::new(RwLock::new(String::from("parallel"))) };
a.name().as_mut_str();
b.name().as_mut_str();
}
This fails to compile with
main2.rs:23:9: 23:18 error: cannot borrow immutable borrowed content as mutable
main2.rs:23 self.name.get_mut().unwrap()
Why can't I call get_mut() to unwrap both the Arc and the RwLock?
Have a better look at the interface of RwLock.
get_mut returns a LockResult<&mut T> which is a guard object. The destruction of this guard automatically unlocks the lock.
In order for things to be safe, the &mut T that you get by calling unwrap() on the guard is borrowing from the guard, that is, the lifetime of the result of unwrap() is limited by that of the guard (since after the guard is destroyed, the lock is unlocked).
And here, you are creating a temporary guard and throwing it away immediately, so the lifetime of the reference cannot exceed that of the function...
Congratz to Rust! Yet another data race prevented at compile-time :)