This question already has answers here:
What's the difference between placing "mut" before a variable name and after the ":"?
(4 answers)
Closed 7 years ago.
Could someone explain what is the difference between these two and when is mut a: &T most often used?
Function parameters and let bindings in Rust are proper patterns, like those at the left of => in match (except that let and parameter patterns must be irrefutable, that is, they must always match). mut a is just a part of pattern syntax and it means that a is a mutable binding. &mut T/&T, on the other hand, is a type - mutable or immutable reference.
There are four possible combinations of mut in references and patterns:
a: &T // immutable binding of immutable reference
mut a: &T // mutable binding of immutable reference
a: &mut T // immutable binding of mutable reference
mut a: &mut T // mutable binding of mutable reference
The first variant is absolutely immutable (without taking internal mutability of Cell and such into account) - you can neither change what a points to nor the object it currently references.
The second variant allows you to change a to point somewhere else but it doesn't allow you to change the object it points to.
The third variant does not allow to change a to point to something else but it allows mutating the value it references.
And the last variant allows both changing a to reference something else and mutating the value this reference is currently pointing at.
Taking the above into account you can see where mut a: &T can be used. For example, you can write a search of a part of a string in a loop for the further usage like this:
let mut s: &str = source;
loop {
// ... whatever
s = &source[i..j];
}
// use the found s here
Related
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.
I understand you're not allowed to create two mutable references to an object at once in Rust. I don't entirely understand why the following code works:
fn main() {
let mut string = String::from("test");
let mutable_reference: &mut String = &mut string;
mutable_reference.push_str(" test");
// as I understand it, this creates a new mutable reference (2nd?)
test(&mut *mutable_reference);
println!("{}", mutable_reference);
}
fn test(s: &mut String) {
s.push_str(" test");
}
The rule
There shall only be one usable mutable reference to a particular value at any point in time.
This is NOT a spatial exclusion (there CAN be multiple references to the same piece) but a temporal exclusion.
The mechanism
In order to enforce this, &mut T is NOT Copy; therefore calling:
test(mutable_reference);
should move the reference into test.
Actually doing this would make it unusable later on and not be very ergonomic, so the Rust compiler inserts an automatic reborrowing, much like you did yourself:
test(&mut *mutable_reference);
You can force the move if you wanted to:
test({ let x = mutable_reference; x });
The effect
Re-borrowing is, in essence, just borrowing:
mutable_reference is borrowed for as long as the unnamed temporary mutable reference exists (or anything that borrows from it),
the unnamed temporary mutable reference is moved into test,
at the of expression, the unnamed temporary mutable reference is destroyed, and therefore the borrow of mutable_reference ends.
Is there more than one mutable pointer somewhere in memory referring to the same location? Yes.
Is there more than one mutable pointer in the code to the same location which is usable? No.
Re-borrowing a mutable pointer locks out the one you're re-borrowing from.
I analyzed the differences in MIR between test(mutable_reference) and test(&mut *mutable_reference). It appears that the latter only introduces an additional level of indirection:
When you are using an extra dereference in the function call, it doesn't create a mutable reference that holds; in other words, it doesn't cause any actual difference outside the function call.
I understand you're not allowed to create two mutable references to an object at once in Rust. I don't entirely understand why the following code works:
fn main() {
let mut string = String::from("test");
let mutable_reference: &mut String = &mut string;
mutable_reference.push_str(" test");
// as I understand it, this creates a new mutable reference (2nd?)
test(&mut *mutable_reference);
println!("{}", mutable_reference);
}
fn test(s: &mut String) {
s.push_str(" test");
}
The rule
There shall only be one usable mutable reference to a particular value at any point in time.
This is NOT a spatial exclusion (there CAN be multiple references to the same piece) but a temporal exclusion.
The mechanism
In order to enforce this, &mut T is NOT Copy; therefore calling:
test(mutable_reference);
should move the reference into test.
Actually doing this would make it unusable later on and not be very ergonomic, so the Rust compiler inserts an automatic reborrowing, much like you did yourself:
test(&mut *mutable_reference);
You can force the move if you wanted to:
test({ let x = mutable_reference; x });
The effect
Re-borrowing is, in essence, just borrowing:
mutable_reference is borrowed for as long as the unnamed temporary mutable reference exists (or anything that borrows from it),
the unnamed temporary mutable reference is moved into test,
at the of expression, the unnamed temporary mutable reference is destroyed, and therefore the borrow of mutable_reference ends.
Is there more than one mutable pointer somewhere in memory referring to the same location? Yes.
Is there more than one mutable pointer in the code to the same location which is usable? No.
Re-borrowing a mutable pointer locks out the one you're re-borrowing from.
I analyzed the differences in MIR between test(mutable_reference) and test(&mut *mutable_reference). It appears that the latter only introduces an additional level of indirection:
When you are using an extra dereference in the function call, it doesn't create a mutable reference that holds; in other words, it doesn't cause any actual difference outside the function call.
I suppose this question is about lifetimes in general, but I'm having difficulty with closures specifically because you can't write out their type.
This example is a bit contrived - I'm just starting to learn Rust, and this is something I've been hung up on.
This program won't compile:
fn main () {
let mut list: Vec<&Fn() -> i32> = Vec::new();
{
list.push(&|| 1);
}
}
Because:
src/main.rs:5:25: 5:24 error: borrowed value does not live long enough
src/main.rs:5 list.push(&|| 1);
^~~~
src/main.rs:2:50: 7:2 note: reference must be valid for the block suffix following statement 0 at 2:49...
src/main.rs:2 let mut list: Vec<&Fn() -> i32> = Vec::new();
src/main.rs:3
src/main.rs:4 {
src/main.rs:5 list.push(&move || 1);
src/main.rs:6 }
src/main.rs:7 }
src/main.rs:5:9: 5:26 note: ...but borrowed value is only valid for the statement at 5:8
src/main.rs:5 list.push(&|| 1);
^~~~~~~~~~~~~~~~~
src/main.rs:5:9: 5:26 help: consider using a `let` binding to increase its lifetime
src/main.rs:5 list.push(&|| 1);
^~~~~~~~~~~~~~~~~
What I gather from this error is that the closure's lifetime is limited to the
statement inside the block, but it needs to live for the entire body of main.
I know (or, I think) that passing the closure to push as a reference means that push is only borrowing the closure, and that ownership will be returned to the block. This code would work if I could just give the closure to push (i.e. if push took ownership of the closure), but since a closure isn't sized, I must pass it as a reference.
Is that right? How can I make this code work?
There are two things you are asking about:
specifying a typename for something that has no specifyable typename
letting a closure live longer than the block where it's defined.
The first issue is fixed by NOT specifying the typename, and letting rust's type inference do the work.
let mut list: Vec<_> = Vec::new();
The second issue is fixed by not trying to make the closure live longer, but by making it "by value" so you can move it. This enforces that your closure does not reference anything, but owns all the captured values.
for i in 0..10 {
list.push(move || i);
}
Now this gives us a new problem. If we add a different closure to the Vec, the types won't match. Therefore to achieve that, we need to box the closures.
fn main () {
let mut list: Vec<Box<Fn() -> i32>> = Vec::new();
for i in 0..10 {
list.push(Box::new(move|| i));
}
{
list.push(Box::new(move|| 42));
}
}
Borrows do not own the thing they point to. Your problem is that you're borrowing a temporary which is going to cease to exist right after it's borrowed because you haven't stored it anywhere. If it helps, consider that borrows don't borrow values, they borrow storage, and a temporary has only transient storage.
If you want a borrow to something to last for any given period, you must borrow from storage that will last at least that long. In this case, because you want to store the borrow in a Vec, this means that whatever storage you borrow from must outlive the Vec as well. Thus:
fn main () {
let closure;
let mut list: Vec<&Fn() -> i32> = Vec::new();
{
closure = || 1;
list.push(&closure);
}
}
Note that closure is defined before list is. In Rust, values are dropped in reverse lexical order at the end of their scope, so any variable defined after list will necessarily be dropped before it, thus leading to list containing invalid pointers.
If you want to push multiple closures, you will need a separate variable for each one.
To forestall a possible "my actual problem isn't this simple" addendum (:P): f you need to return list or in some way persist it beyond a single function call, note that there is no way to extend a borrow. In that case, what you need to do is change list to a vector of owned, boxed closures (i.e. Vec<Box<Fn() -> i32>>).
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)