Dereferencing a boxed struct and moving its field causes it to be moved, but doing it in another way works just fine. I don't understand the difference between these two pop functions. How does one fail when the other one doesn't?
pub struct Stack<T> {
head: Option<Box<Node<T>>>,
len: usize,
}
struct Node<T> {
element: T,
next: Option<Box<Node<T>>>,
}
impl<T> Stack<T> {
pub fn pop(&mut self) -> Option<T> {
self.head.take().map(|boxed_node| {
let node = *boxed_node;
self.head = node.next;
node.element
})
}
pub fn pop_causes_error(&mut self) -> Option<T> {
self.head.take().map(|boxed_node| {
self.head = (*boxed_node).next;
(*boxed_node).element
})
}
}
error[E0382]: use of moved value: `boxed_node`
--> src/main.rs:22:13
|
21 | self.head = (*boxed_node).next;
| ------------------ value moved here
22 | (*boxed_node).element
| ^^^^^^^^^^^^^^^^^^^^^ value used here after move
|
= note: move occurs because `boxed_node.next` has type `std::option::Option<std::boxed::Box<Node<T>>>`, which does not implement the `Copy` trait
You can only move out of a box once:
struct S;
fn main() {
let x = Box::new(S);
let val: S = *x;
let val2: S = *x; // <-- use of moved value: `*x`
}
In the first function, you moved the value out of the box and assigned it to the node variable. This allows you to move different fields out of it. Even if one field is moved, other fields are still available. Equivalent to this:
struct S1 {
a: S2,
b: S2,
}
struct S2;
fn main() {
let x = Box::new(S1 { a: S2, b: S2 });
let tmp: S1 = *x;
let a = tmp.a;
let b = tmp.b;
}
In the second function, you move the value to the temporary (*boxed_node) and then move a field out of it. The temporary value is destroyed immediately after the end of the expression, along with its other fields. The box doesn't have the data anymore, and you don't have a variable to take the other field from. Equivalent to this:
struct S1 {
a: S2,
b: S2,
}
struct S2;
fn main() {
let x = Box::new(S1 { a: S2, b: S2 });
let tmp: S1 = *x;
let a = tmp.a;
let tmp: S1 = *x; // <-- use of moved value: `*x`
let b = tmp.b;
}
Some good news is that non-lexical lifetimes will allow your original code to work:
pub struct Stack<T> {
head: Option<Box<Node<T>>>,
len: usize,
}
struct Node<T> {
element: T,
next: Option<Box<Node<T>>>,
}
impl<T> Stack<T> {
pub fn pop_no_longer_causes_error(&mut self) -> Option<T> {
self.head.take().map(|boxed_node| {
self.head = (*boxed_node).next;
(*boxed_node).element
})
}
}
NLL enhances the borrow checker to better track the moves of variables.
Related
As a beginner in rust I am trying to implement basic data structures. Here I am trying to implement a stack. Here are the structs I am using
#[derive(Debug, Clone)]
struct Node<T: std::marker::Copy> {
value: T,
next: Option<Box<Node<T>>>,
}
impl<T: std::marker::Copy> Node<T> {
fn new(value: T) -> Node<T> {
Node { value, next: None }
}
}
#[derive(Debug, Clone)]
struct Stack<T: std::marker::Copy> {
first: Option<Box<Node<T>>>,
last: Option<Box<Node<T>>>,
size: usize,
}
Now, in push() function, what I'm trying to do is, if there is no first and last, put the newly created Node as the new first and last. If they exist already, create a new variable temp which holds the current first, put the new Node as the new value in first, and put the previous first's next value as temp. Here is my push().
impl<T: std::marker::Copy> Stack<T> {
fn push(&mut self, elem: T) -> usize {
if self.first.is_none() {
self.first = Some(Box::new(Node::new(elem)));
self.last = Some(Box::new(Node::new(elem)));
} else {
let temp = self.first.take();
self.first = Some(Box::new(Node::new(elem)));
self.first.unwrap().next = Some(Box::new(*temp.unwrap())); //problem in this line
}
self.size += 1;
self.size
}
}
Here when I'm trying to assign the next value, I'm getting the error
cannot move out of `self.first` which is behind a mutable reference
--> src/bin/stack.rs:36:13
|
36 | self.first.unwrap().next = Some(Box::new(*temp.unwrap()));
| ^^^^^^^^^^ move occurs because `self.first` has type `Option<Box<Node<T>>>`, which does not implement the `Copy` trait
|
help: consider borrowing the `Option`'s content
|
36 | self.first.as_ref().unwrap().next = Some(Box::new(*temp.unwrap()));
| +++++++++
Using as_ref() further increases the error as it can't assign data in a refernce. How can I correct this and what am I doing wrong?
You're probably looking for std::mem::replace https://doc.rust-lang.org/std/mem/fn.replace.html
It allows you to replace the data pointed to by a &mut T with a T, and returns the original data as an owned T.
For example:
let mut s = String::from("hello");
let new_str = String::from("new");
let old_str: String = std::mem::replace(&mut s, new_str);
assert_eq!(s, "new");
assert_eq!(old_str, "hello");
P.S why not use a Vec<T> (unless you're using a linked list for learning purposes). It has a simple API, and performance will be significantly better in the vast majority of cases
P.P.S. If you're implementing a linked list for learning purposes, check out https://rust-unofficial.github.io/too-many-lists/
maybe there is a better way but I used a combination of RefCell and std::mem:replace to get around the error, wrapping your fields with RefCell will allow you to get mutable reference that you can then pass to replace to perform the memory change. Here is the code
use std::cell::RefCell;
use std::mem::replace;
#[derive(Debug, Clone)]
struct Node<T: std::marker::Copy> {
value: T,
next: RefCell<Option<Box<Node<T>>>>,
}
impl<T: std::marker::Copy> Node<T> {
fn new(value: T) -> Node<T> {
Node { value, next: RefCell::new(None) }
}
}
#[derive(Debug, Clone)]
struct Stack<T: std::marker::Copy> {
first: RefCell<Option<Box<Node<T>>>>,
last: RefCell<Option<Box<Node<T>>>>,
size: usize,
}
impl<T: std::marker::Copy> Stack<T> {
fn push(&mut self, elem: T) -> usize {
if self.first.borrow().is_none() {
self.first = RefCell::new(Some(Box::new(Node::new(elem))));
self.last = RefCell::new(Some(Box::new(Node::new(elem))));
} else {
let temp =replace(self.first.get_mut(),None);
self.first = RefCell::new(Some(Box::new(Node::new(elem))));
let _=replace(self.first.get_mut(), Some(Box::new(*temp.unwrap())));
}
self.size += 1;
self.size
}
}
Code:
use std::collections::HashSet;
use std::{mem, ptr, fmt};
use std::ops::Deref;
enum Unsafety {
Normal
}
enum ImplPolarity { Positive }
struct TraitRef;
struct Ty;
struct ImplItem;
enum ItemKind {
Impl(Unsafety,
ImplPolarity,
Option<TraitRef>, // (optional) trait this impl implements
Box<Ty>, // self
),
}
struct Item {
node: ItemKind,
}
pub struct P<T: ?Sized> {
ptr: Box<T>
}
impl<T: 'static> P<T> {
pub fn unwrap(self) -> T {
*self.ptr
}
}
impl<T: ?Sized> Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
fn main() {
let mut items = Vec::<P<Item>>::new();
let mut item2: Item;
for item in items.drain(..) {
if let ItemKind::Impl(Unsafety::Normal,
ImplPolarity::Positive,
Some(ref trait_type),
ref for_type) = item.node {
} else {
// item2 = *item; // AAA
item2 = item.unwrap(); // BBB
}
}
}
Produce the compile-time error:
error[E0505]: cannot move out of `item` because it is borrowed
--> /home/xxx/.emacs.d/rust-playground/at-2017-07-29-204629/snippet.rs:64:21
|
61 | ref for_type) = item.node {
| ---- borrow of `item` occurs here
...
64 | item2 = item.unwrap();
I do not understand two things:
Why does it complain about the borrow in the if branch while we in else branch? They are supposed to be mutually exclusive, and a borrow in one should not influence another.
If I replace Vec in let mut items = Vec::<P<Item>>::new(); with Vec<Box<Item>> and uncomment line AAA and comment line BBB, then it compiles. Both Box and P implement Deref, so the item.node expression should be the same.
Here's a much clearer example:
struct Item;
struct P<T> {
ptr: Box<T>,
}
impl<T> P<T> {
fn new(v: T) -> Self {
P { ptr: Box::new(v) }
}
}
impl<T> std::ops::Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
fn main() {
let mut item = P::new(Item);
// let mut item = Box::new(Item);
*item;
}
Both Box and P implement Deref, so the item.node expression should be the same.
Hard truth time: moving out of Box is special-cased in the compiler. It does not use Deref. Moving out of a Box deallocates the memory and gives you ownership. It is not possible to implement this special ability ourselves.
Maybe at some point in the future a hypothetical trait like DerefMove will be added. This trait is hard to get right. There have been a number of attempts for an RFC for it, but none are currently open.
See also:
Dereferencing Box<T> gives back value instead of reference
How can I reuse a box that I have moved the value out of?
This question already has an answer here:
Error while trying to borrow 2 fields from a struct wrapped in RefCell
(1 answer)
Closed 3 years ago.
I have a struct with two vectors that is passed through a function while in a Arc<Mutex<TwoArrays>>.
pub struct TwoArrays {
pub a: Vec<i32>,
pub b: Vec<i32>,
}
fn add_arrays(mut foo: Arc<Mutex<TwoArrays>>) {
let mut f = foo.lock().unwrap();
//Loop A: compiles
for i in 0..f.a.len() {
for j in 0..f.b.len() {
f.b[j] += f.a[i];
}
}
//Loop B: does not compile
for i in f.a.iter() {
for j in 0..f.b.len() {
f.b[j] += i;
}
}
}
When I make a loop that uses an iterator, with another loop writing inside(Loop B), the compiler complains:
error[E0502]: cannot borrow `f` as mutable because it is also borrowed as immutable
Loop A Compiles.
Why is there a immutable borrow on f?
Can I make it only borrow each array individually? That is, a mutable borrow of f.b and a immutable borrow of f.a?
Why does this not happen when I pass TwoArrays directly? It only happens when I pass it in as an Arc<Mutex<TwoArrays>>
When you unwrap the LockResult you get a MutexGuard, and not directly a TwoArrays. You can use it as if it was a TwoArrays because it implements Deref and DerefMut.
When you try to write 2 loops, you try to use both deref and deref_mut at once: that's impossible:
pub struct TwoArrays {
pub a: Vec<i32>,
pub b: Vec<i32>,
}
fn add_arrays(mut foo: Arc<Mutex<TwoArrays>>) {
let mut f = foo.lock().unwrap();
//Loop B: does not compile
for i in f.a.iter() {
// ^~~~~~~~~~~~~~~~~~~ Implicit call to `deref` here.
for j in 0..f.b.len() {
// ^~~~~~~~~~~~ Another implicit call to `deref` here.
f.b[j] += i;
// ^~~~~~~~~~~~~~~~~~~~ Implicit call to `deref_mut` here.
}
}
}
If you deref_mut once before doing the loops, everything works fine:
use std::{sync::{Arc, Mutex}, ops::DerefMut};
pub struct TwoArrays {
pub a: Vec<i32>,
pub b: Vec<i32>,
}
fn add_arrays(foo: &mut Arc<Mutex<TwoArrays>>) {
let mut mutex_guard = foo.lock().unwrap();
let real_two_arrays = mutex_guard.deref_mut();
for i in &mut real_two_arrays.a {
for j in &real_two_arrays.b {
*i += *j;
}
}
}
You can access to two vector in a struct like following:
use std::mem;
#[derive(Debug)]
pub struct TwoArrays {
pub a: Vec<i32>,
pub b: Vec<i32>,
}
fn add_arrays(mut foo: TwoArrays) {
let a = foo.a.clone();
let mut b = foo.b.clone();
for i in a.iter() {
let mut index = 0;
for _j in b.iter_mut() {
let mut new_value = i.clone() + foo.b[index as usize].clone();
mem::swap(&mut foo.b[index as usize], &mut new_value);
index = index + 1;
}
}
println!("Arrays A: {:?}", &foo.a);
println!("Arrays A: {:?}", &foo.b);
}
fn main() {
let a = vec![1i32, 2i32, 3i32];
let b = vec![4i32, 5i32, 6i32];
let two_arrays = TwoArrays { a, b };
// let foo = Arc::new(Mutex::new(two_arrays));
add_arrays(two_arrays);
}
Playground
Why is there an immutable borrow for f?
Because you tried to iterate it with iter() not the iter_mut()
And why does this not happen when I pass TwoArrays directly? It only happens when I pass it in as an Arc<Mutex<TwoArrays>>
You can pass it as naked struct without the need of Arc<Mutex<>> with the sample code.
If you insist on using Arc<Mutex<>> to pass the same object around with an atomic reference you can change the function signature to the following:
fn add_arrays(mut foo: Arc<Mutex<TwoArrays>>)
And you need to lock() and get that reference from the Arc with following:
let foo = foo.lock().unwrap();
Playground With Arc Usage
I know about the great Rust feature:
Foo {
fieldX: someValue,
..Self::default()
}
I want to use this in a method with &mut self, not touching fields f10 and f11 and setting the others to default:
#[derive(Default)]
struct Foo {
f1: u32,
//...
f10: Vec<u32>,
f11: Vec<u32>,
}
impl Foo {
fn f1(&mut self) {
let new_me = Foo {
f10: self.f10,
..Self::default()
};
*self = new_me;
}
}
but the compiler says:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:12:18
|
12 | f10: self.f10,
| ^^^^ cannot move out of borrowed content
How can I:
Leave signature of f1 as is: &mut self
Not copy any Vec<>, only moving
Not write boring code, like
self.f1 = 0;
self.f2 = 0;
self.f3 = None;
// ...
I'd replace the entire self with the default value, then preserve the interesting fields from the previous value:
use std::mem;
impl Foo {
fn f1(&mut self) {
let old = mem::replace(self, Self::default());
self.f10 = old.f10;
}
}
It seems that if you borrow a reference to a struct field, the whole struct is considered borrowed. I've managed to isolate and example of what I want to do. I just want to get a "read-only" reference to a field in B to obtain some data and then modify another field of B. Is there a idiomatic Rust way to do this?
struct A {
i: i32,
}
struct B {
j: i32,
a: Box<A>,
}
impl B {
fn get<'a>(&'a mut self) -> &'a A {
&*self.a
}
fn set(&mut self, j: i32) {
self.j = j
}
}
fn foo(a: &A) -> i32 {
a.i + 1
}
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let a_ref = b.get();
b.set(foo(a_ref));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> src/main.rs:27:5
|
26 | let a_ref = b.get();
| - first mutable borrow occurs here
27 | b.set(foo(a_ref));
| ^ second mutable borrow occurs here
28 | }
| - first borrow ends here
It's a feature of the language. From the compiler point of view, there is no way for it to know that it's safe to call your set() function while a is borrowed via get().
Your get() function borrows b mutably, and returns a reference, thus b will remain borrowed until this reference goes out of scope.
You have several way of handling this:
Separate your two fields into two different structs
Move the code which needs to access both attribute inside a method of B
Make your attributes public, you will thus be able to directly get references to them
Compute the new value before setting it, like this:
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let newval = {
let a_ref = b.get();
foo(a_ref)
};
b.set(newval);
}
Expanding a bit on Levans' answer
Move the code which needs to access both attribute inside a method of B
That might look like this at a first pass:
impl B {
fn do_thing(&mut self) {
self.j = self.a.foo()
}
}
However, this hard-codes the call to foo. You could also accept a closure to allow this to be more flexible:
impl B {
fn update_j_with_a<F>(&mut self, f: F)
where
F: FnOnce(&mut A) -> i32,
{
self.j = f(&mut self.a)
}
}
// ...
b.update_j_with_a(|a| a.foo())
Separate your two fields into two different structs
This is also applicable when you have borrowed two disjoint subsets of attributes. For example:
struct A {
description: String,
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.build_description()
// cannot borrow `*self` as immutable because `self.description` is also borrowed as mutable
}
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
Can be changed into
struct A {
description: String,
info: Info,
}
struct Info {
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.info.build_description()
}
}
impl Info {
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
You can combine these two steps (and I'd say that it's better practice) and move the method onto the inner struct.