let mut set = HashSet::<u32>::new();
let a = set.get(&1);
set.remove(&1);
a.unwrap(); // cannot borrow `set` as mutable because it is also borrowed as immutable
Here is my code. I see what the error means and why rust prevent me doing it.
But I can't find any type annotation in set.rs to make that error happen.
pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
where T: Borrow<Q>,
Q: Hash + Eq
This is the declaration of set.get but I can't see anything relevant.
The important part of get is the following: -> Option<&T>.
Contrary to what you seem to be believing, this method gives you a reference, not the actual object (and doing so also establishes an immutable borrow on the item). As a result, when you then remove() said object (and get a mutable borrow over the collection), the reference is evidently immediately invalidated, and as a result, it is impossible for you to unwrap() it.
You may be looking to take() the set element instead of get(). This will return the object and remove the item from the set, instead of returning a reference; it also means that you will no longer need the call to remove() either (playground):
let mut set = HashSet::<u32>::new();
set.insert(1);
let a = set.take(&1).unwrap();
Related
The following code gives me the "Assignment to borrowed a" error. Hows the compiler able to know that? Is the compiler special casing RefCell or is there something in the language that allows it to tell the compiler you have a borrowed value?
use std::cell::RefCell;
fn main() {
let mut a = RefCell::new(A{a:5});
let mut b = a.borrow_mut();
a = RefCell::new(A{a:6});
}
Also, why does this code work which seems to be doing the exact same thing?
use std::cell::RefCell;
fn main() {
let mut a = Box::new(A{a:5});
let mut b = &mut a;
a = Box::new(A{a:6});
}
The compiler is not special casing RefCell. But borrow_mut() has the following signature:
pub fn borrow_mut(&self) -> RefMut<'_, T>
So it returns a RefMut that keeps the RefCell borrowed while it is alive (because of the '_, that according to the lifetime elision rules borrows from self). So while it is alive, you cannot assign to the RefCell because it is borrowed.
The reason the second case with a mutable reference works is that since mutable references don't implement Drop (a more precise term is that they don't have a drop glue, that is, neither they implement Drop nor any of their fields (which is none for mutable references) has a drop glue, recursively), the compiler shortens the borrow and drop the reference early. But it cannot do that with the RefMut from the RefCell because it implements Drop, and thus early-dropping it would change program behavior.
First, I tried something like this:
let mut vec = vec![0];
vec.rotate_right(vec.len());
It can't be compiled because:
error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
I thought that the Rust borrow checker could be smarter than this, so I found something called NLL, and it should solve this problem.
I tried the sample:
let mut vec = vec![0];
vec.resize(vec.len(), 0);
It could work, but why is it not working with rotate_right? Both of them take a &mut self. What's going on?
It is definitely an interesting one.
They are similar - but not quite the same. resize() is a member of Vec. rotate_right(), on the other hand, is a method of slices.
Vec<T> derefs to [T], so most of the time this does not matter. But actually, while this call:
vec.resize(vec.len(), 0);
Desugars to something like:
<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
This call:
vec.rotate_right(vec.len());
Is more like:
<[i32]>::rotate_right(
<Vec<i32> as DerefMut>::deref_mut(&mut vec),
<Vec<i32>>::len(&vec),
);
But in what order?
This is the MIR for rotate_right() (simplified a lot):
fn foo() -> () {
_4 = <Vec<i32> as DerefMut>::deref_mut(move _5);
_6 = Vec::<i32>::len(move _7);
_2 = core::slice::<impl [i32]>::rotate_right(move _3, move _6);
}
And this is the MIR for resize() (again, simplified a lot):
fn foo() -> () {
_4 = Vec::<i32>::len(move _5);
_2 = Vec::<i32>::resize(move _3, move _4, const 0_i32);
}
In the resize() example, we first call Vec::len() with a reference to vec. This returns usize. Then we call Vec::resize(), when we have no outstanding references to vec, so mutably borrowing it is fine!
However, with rotate_right(), first we call <Vec<i32> as DerefMut>::deref_mut(&mut vec). This returns &mut [i32], with its lifetime tied to vec. That is, as long as this reference (mutable reference!) is alive, we are not allowed to use have any other reference to vec. But then we try to borrow vec in order to pass the (shared, but it doesn't matter) reference to Vec::len(), while we still need to use the mutable reference from deref_mut() later, in the call to <[i32]>::rotate_right()! This is an error.
This is because Rust defines an evaluation order for operands:
Expressions taking multiple operands are evaluated left to right as written in the source code.
Because vec.resize() is actually (&mut *vec).rotate_right(), we first evaluate the dereference+reference, then the arguments:
let dereferenced_vec = &mut *vec;
let len = vec.len();
dereferencec_vec.rotate_right(len);
Which is obviously a violation of the borrow rules.
On the other hand, vec.resize(vec.len()) has no work to do on the callee (vec), and so we first evaluate vec.len(), and then the call itself.
Solving this is as easy as extracting the vec.len() to a new line (new statement, to be precise), and the compiler also suggests that.
The only structural difference between these two calls is the target: rotate_right() is defined on a slice, while resize() is defined on a Vec. This means that the non-working case has an additional Deref coercion (in this case DerefMut) that must pass the borrow checker.
This is actually outside the realm of non-lexical lifetime rules since how long the references live is not important. This curiosity would fall under evaluation order rules; more specifically, given vec.rotate_right(vec.len()), when does the coercion from &mut Vec<_> to &mut [_] occur? Before or after vec.len()?
Evaluation order for function and method calls is left-to-right, so the coercion must be evaluated before the other parameters, meaning vec is already mutably borrowed before vec.len() is called.
use std::cell::RefCell;
use std::rc::Weak;
struct Elem {
attached_elem: Weak<RefCell<Elem>>,
value: i32,
}
impl Elem {
fn borrow_mut_attached_elem(&self) -> &mut Elem {
//what should this line be?
self.attached_elem.upgrade().unwrap().borrow_mut()
}
}
fn main(){}
I have tried some similar other lines but nothing has worked so far, even the experimental cell_leak feature for RefMut.
I don't mind changing the signature of the function I just want to reduce the overhead of getting a mutable reference to the attached_elem from an Elem.
what should this line be?
There is nothing you can put in that line to (safely) satisfy the function signature - and that's for good reason. While RefCell does allow obtaining &mut T from a RefCell<T> (that's why it exists), it must guarantee that only one mutable reference exist at a time. It does so by only providing a temporary reference whose lifetime is tied to the RefMut<T> wrapper. Once the wrapper is dropped, the value is marked as no longer borrowed, so the reference must not outlive it.
If Rust were to allow you to return a naked &mut Elem, you'd be able to use the reference after the RefCell has ceased being marked as borrowed. In that case, what's to stop you from calling borrow_mut_attached_elem() again, and obtain a second mutable reference to the same Elem?
So you'll definitely need to change the signature. If you just need to give outside code temporary access to &mut Elem, the easiest way is to accept a closure that will receive it. For example:
fn with_attached_elem<R>(&self, f: impl FnOnce(&mut Elem) -> R) -> R {
let rc = self.attached_elem.upgrade().unwrap();
let retval = f(&mut *rc.borrow_mut());
retval
}
You'd call it to do something with the element, e.g.:
elem.with_attached_elem(|e| e.value += 1);
with_attached_elem takes care to return the value returned by the closure, allowing you to collect data from &mut Elem and propagate it to the caller. For example, to pick up the value of the attached element you could use:
let value = elem.with_attached_elem(|e| e.value);
Consider this code (Rust Playground):
#[derive(Clone, Copy, Debug)]
struct X(i32);
impl std::ops::AddAssign for X {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
fn main() {
let mut ary_i32 = [1_i32; 2];
ary_i32[0] += ary_i32[1]; // OK
let mut ary_x = [X(1); 2];
ary_x[0] += ary_x[1]; // OK
let mut vec_i32 = vec![1_i32; 2];
vec_i32[0] += vec_i32[1]; // OK
let mut vec_x = vec![X(1); 2];
vec_x[0] += vec_x[1]; // error[E0502]: cannot borrow `vec_x` as immutable because it is also borrowed as mutable
}
Why I get E0502 only on vec_x line?
I could not understand why only the operations for ary_x and vec_i32 are permitted. Does borrow checker treat builtin types (i32, array) specially?
I researched some resources and read MIR of my code, and managed to understand what is going on.
The comment by #trentcl will be the best answer.
I write the details as possible.
For array, Index and IndexMut traits are not used and compiler directly manipulates array elements (you can see this with MIR). So, borrowing problem does not exist here.
Explanating for Vec, rustc guide is useful.
First, Two-phase borrow is not applied to vec_foo[0] += vec_foo[1] statement.
And, the difference between i32 and X is caused by operator lowering.
Basically, statements like vec_user_defined[0] += vec_user_defined[1] are converted to function calls like add_assign(index_mut(...), *index(...)), and function arguments are evaluated from left to right. So, index_mut() borrows x mutably and index() tries to borrow x, and fails.
But for builtin types like i32, compound assignment operator is not converted to function call, and rhs is evaluated before lhs (you can see index() is called before index_mut() with MIR). So, for builtin types, vec_builtin[0] += vec_builtin[1] works.
I know these things from lo48576's article (Japanese).
I considered some workarounds:
Just use an intermediate variable as #sebpuetz said.
Convert Vec to slice as #trentcl said. But this doesn't work well for multidimensional Vec.
Write some macro to automatically introduce an intermediate variable. I found rhs_first_assign crate does such works.
Rust arrays live on the stack, are predictably sized, and therefore have stronger borrow checker guarantees. Vectors are smart pointers on the stack pointing at data that can grow and shrink on the Heap. Because the final example uses the Vector type, the borrow checker considers the entire Vector as a single mutably borrowed object when loading it from the Heap.
As you've observed, the borrow checker can create a mutable reference to a single element to something living on the Stack, whereas it creates a mutable reference to the Vector's smart pointer on the Stack, and then a further mutable reference to the data on the heap. This is why the immutable reference to vec_vec_x[1][1] fails.
As #sebpuetz noted in a comment, you can solve this by first copying an immutable reference to vec_vec_x[1][1], then creating an immutable reference.
What is my error and how to fix it?
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let mut vals = get_m().iter().peekable();
println!("Saw a {:?}", vals.peek());
}
(playground)
The compiler's error suggests "consider using a let binding" — but I already am:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:6:45
|
6 | let mut vals = get_m().iter().peekable();
| ------- ^ temporary value dropped here while still borrowed
| |
| temporary value created here
7 | println!("Saw a {:?}", vals.peek());
8 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
This is obviously a newbie question -- though I thought I'd written enough Rust at this point that I had a handle on the borrow checker... apparently I haven't.
This question is similar to Using a `let` binding to increase value lifetime, but doesn't involve breaking down an expression into multiple statements, so I don't think the problem is identical.
The problem is that the Peekable iterator lives to the end of the function, but it holds a reference to the vector returned by get_m, which only lasts as long as the statement containing that call.
There are actually a lot of things going on here, so let's take it step by step:
get_m allocates and returns a vector, of type Vec<i8>.
We make the call .iter(). Surprisingly, Vec<i8> has no iter method, nor does it implement any trait that has one. So there are three sub-steps here:
Any method call checks whether its self value implements the Deref trait, and applies it if necessary. Vec<i8> does implement Deref, so we implicitly call its deref method. However, deref takes its self argument by reference, which means that get_m() is now an rvalue appearing in an lvalue context. In this situation, Rust creates a temporary to hold the value, and passes a reference to that. (Keep an eye on this temporary!)
We call deref, yielding a slice of type &[i8] borrowing the vector's elements.
This slice implements the SliceExt trait, which does have an iter method. Finally! This iter also takes its self argument by reference, and returns a std::slice::Iter holding a reference to the slice.
We make the call .peekable(). As before, std::slice::Iter has no peekable method, but it does implement Iterator; IteratorExt is implemented for every Iterator; and IteratorExt does have a peekable method. This takes its self by value, so the Iter is consumed, and we get a std::iter::Peekable back in return, again holding a reference to the slice.
This Peekable is then bound to the variable vals, which lives to the end of the function.
The temporary holding the original Vec<i8>, to whose elements the Peekable refers, now dies. Oops. This is the borrowed value not living long enough.
But the temporary dies there only because that's the rule for temporaries. If we give it a name, then it lasts as long as its name is in scope:
let vec = get_m();
let mut peekable = vec.iter().peekable();
println!("Saw a {:?}", vals.peek());
I think that's the story. What still confuses me, though, is why that temporary doesn't live longer, even without a name. The Rust reference says, "A temporary's lifetime equals the largest lifetime of any reference that points to it." But that's clearly not the case here.
This is happening because you are trying to run your .iter().peekable() on the actual vector inside of get_m(), which is getting re-referenced by vals.
Basically, you want something like this:
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let vals = get_m();
let mut val = vals.iter().peekable();
println!("Saw a {:?}", val.peek());
}
(Playground)
Result:
Saw a Some(1)