This code fails as expected at let c = a; with compile error "use of moved value: a":
fn main() {
let a: &mut i32 = &mut 0;
let b = a;
let c = a;
}
a is moved into b and is no longer available for an assignment to c. So far, so good.
However, if I just annotate b's type and leave everything else alone:
fn main() {
let a: &mut i32 = &mut 0;
let b: &mut i32 = a;
let c = a;
}
the code fails again at let c = a;
But this time with a very different error message: "cannot move out of a because it is borrowed ... borrow of *a occurs here: let b: &mut i32 = a;"
So, if I just annotate b's type: no move of a into b, but instead a "re"-borrow of *a?
What am I missing?
Cheers.
So, if I just annotate b's type: no move of a into b, but instead a "re"-borrow of *a?
What am I missing?
Absolutely nothing, as in this case these two operations are semantically very similar (and equivalent if a and b belong to the same scope).
Either you move the reference a into b, making a a moved value, and no longer available.
Either you reborrow *a in b, making a unusable as long as b is in scope.
The second case is less definitive than the first, you can show this by putting the line defining b into a sub-scope.
This example won't compile because a is moved:
fn main() {
let a: &mut i32 = &mut 0;
{ let b = a; }
let c = a;
}
But this one will, because once b goes out of scope a is unlocked:
fn main() {
let a: &mut i32 = &mut 0;
{ let b = &mut *a; }
let c = a;
}
Now, to the question "Why does annotating the type of b change the behavior ?", my guess would be:
When there is no type annotation, the operation is a simple and straightforward move. Nothing is needed to be checked.
When there is a type annotation, a conversion may be needed (casting a &mut _ into a &_, or transforming a simple reference into a reference to a trait object). So the compiler opts for a re-borrow of the value, rather than a move.
For example, this code is perflectly valid:
fn main() {
let a: &mut i32 = &mut 0;
let b: &i32 = a;
}
and here moving a into b would not make any sense, as they are of different type. Still this code compiles: b simply re-borrows *a, and the value won't be mutably available through a as long as b is in scope.
To complement #Levans's answer on the specific question "Why does annotating the type change the behaviour?":
When you don't write the type, the compiler performs a simple move. When you do put the type, the let statement becomes a coercion site as documented in "Coercion sites":
Possible coercion sites are:
let statements where an explicit type is given.
In the present case the compiler performs a reborrow coercion, which is a special case of coercion going from &mut to &mut, as explained in this issue comment on GitHub.
Note that reborrowing in general and reborrow coercion in particular are currently poorly documented. There is an open issue on the Rust Reference to improve that point.
Related
this is simple code which shows error cannot assign to a because it is borrowed assi gnment to borrowed a occurs here. Can it be possible to assign value if it is borrowed?
fn main() {
let mut a = 20;
let b = &a;
a = 20;
println!("{}, {}", a, b);
}
Not without interior mutability.
Disallowing mutation of a value that is borrowed prevents many different kinds of bugs. For example, you cannot push onto a Vec while you have a shared reference to a value in the Vec. This seems arbitrary, but if pushing causes an internal reallocation, previously-dispensed references would become dangling.
Here's what the interior mutability approach would look like:
use std::cell::Cell;
fn main() {
let a = Cell::new(20);
let b = &a;
a.set(10);
println!("{}, {}", a.get(), b.get());
}
Note a doesn't even have to be declared mut, because cells can be mutated through a shared reference.
Rust enforces "multiple readers or single writer" rule at compile time. As long as there is mutable reference to a value you cannot use the owner until the mutable reference goes away. Similarly as long as there is multiple shared references to value not even it's owner can modify it. For example, this would compile.
fn main() {
let mut a = 20;
{
let b = &a;
println!("{}", b);
} // Shared reference goes out of scope here
a = 20;
println!("{}", a);
}
I'm currently writing a simple function to swap numbers in Rust:
fn swapnumbers() {
let a = 1;
let b = 2;
let (a, b) = (b, a);
println!("{}, {}", a, b);
}
I am now trying to make a test for it, how do I do it? All my other attempts have failed.
I would suggest modifying the function to return something instead of printing it, and then using either the assert_eq! or assert! macros to test for proper function. (docs for assert_eq!, docs for assert!)
fn swapnumbers() -> (i32, i32) {
let a = 1;
let b = 2;
let (a, b) = (b, a);
return (a, b);
}
assert_eq!(swapnumbers(), (2, 1));
(-> (i32, i32) means that this function returns a tuple of two i32s)
And if you're unfamiliar with testing in Rust, the official Rust book tutorial can help you out with that!
If you want to actually swap numbers, you would need to do something like this:
fn swapnumbers(a: &mut i32, b: &mut i32) {
std::mem::swap(a, b);
}
Note the types specified after the parameter names. &mut i32 means the passed value must be a mutable reference of an i32 The parameter must be mutable for you to be able to assign to it and change its value, and it must be a reference so that the function does not actually take ownership of the data.
When I wondered how a mutable reference could move into a method, all the questions began.
let a = &mut x;
a.somemethod(); // value of a should have moved
a.anothermethod(); // but it works.
I've googled a lot. (really a lot)
And I've noticed that a mutable reference passed as a parameter to a function, always undergoes the following transformation. (which is called reborrowing)
fn test(&mut a) -> ();
let a = &mut x;
test(a); // what we write in code.
test(&mut *a); // the actual action in code.
So, I have googled more about "reborrowing", for its detail.
And this is what I've got.
In any of codes, x refers to an arbitrary data. I don't mention it because I don't think the type of it is important for discussion. (However, I used i32 in my own).
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
So alright. It's quite interesting. It seems like b borrows not only x but also a.
Perhaps, we can clarify reborrowing like this : &'a *(&'b mut x).
It has borrowed x (which has a lifetime 'a in here),
but also borrowed a (which has a lifetime 'b).
So I ran the following code to confirm my conjecture.
let x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
But this works!
What??
But I just decided to get this.
&'a mut *&mutx, not &'a mut *&'b mutx.
I had no idea why mut x is unavailable during the lifetime of &mut *&mutx nor why mut x is re-available after the lifetime of &mut *&mutx, but "okay, let's just say so".
But look at this. It's totally out of my mind for a clear and general understanding.
let x: i32 = 1;
let b;
{
let a = &mut x;
let b = &**&a;
} // error!! a should live longer than b!
Wasn't lifetime simply relying on what the real data b is referring to???
&'a **& &mut x, not &'a **&'b &'c mut x.
And now what??
&'a **&'b &mut x ??? (which was my guess).
How should I accept this complicated situation?
These are some great questions! I'll do my best to answer the ones I can.
The Rust Reference is a great place for finding answers to questions like this, about the deeper semantics of Rust.
First, for your question about method resolution, the Reference
says:
When looking up a method call, the receiver may be automatically
dereferenced or borrowed in order to call a method. This requires a
more complex lookup process than for other functions, since there may
be a number of possible methods to call. The following procedure is
used:
The first step is to build a list of candidate receiver types. Obtain
these by repeatedly dereferencing the receiver
expression's type, adding each type encountered to the list, then
finally attempting an unsized coercion at the end, and adding the
result type if that is successful. Then, for each candidate T, add
&T and &mut T to the list immediately after T.
For instance, if the receiver has type Box<[i32;2]>, then the
candidate types will be Box<[i32;2]>, &Box<[i32;2]>, &mut Box<[i32;2]>, [i32; 2] (by dereferencing), &[i32; 2], &mut [i32; 2], [i32] (by unsized coercion), &[i32], and finally &mut [i32].
The link above goes into more detail.
For the rest of your questions, I think this is mostly about type coercion. Some relevant coercions are:
&mut T to &T
&T or &mut T to &U if T implements Deref<Target = U>
&mut T to &mut U if T implements DerefMut<Target = U>
Notably, &U and &mut U both implement Deref<Target = U>, and &mut U also implements DerefMut<Target = U>. Therefore, the second/third rules lead to the following coercions:
Let T be:
Coerce from
To
&U
&&U
&U
&U
&mut &U
&U
&mut U
&&mut U
&U
&mut U
&mut &mut U
&mut U
Now with the reference out of the way, let's look at your questions in more detail:
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
In order to write into a reference, it clearly must be a mutable (aka unique) reference. When you write let a = &mut x, now a is the only way to access x. Now when you write let b = &mut *a, it essentially means let b = &mut *(&mut x), which simplifies to let b = &mut x.
Here, b mutably borrows a, Rust will not let you use a until b is destroyed... or so it seems for now.
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
Here, let b = &*a turns into let b = &*(&mut x), so let b = &x. No matter what kind of reference b is, a is a mutable reference and must be unique, so you can't use it until b is gone (out of scope).
let mut x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
(I assume you meant let mut x).
Now this is where it gets interesting. Here, since a and b both mutably point to the same object, Rust will not let you use a until b is destroyed. It seems like the reasoning should be, "since b mutably borrows a", but that's actually not the case. Normally, b would in fact borrow a, and this is the case for smart pointers like Box, std::cell::RefMut, etc. However, references get special treatment: Rust can analyze the memory they point to.
So when you write let b = &mut *a, b doesn't actually borrow a! It only borrows the data a points to. This distinction wasn't relevant before, but here it is what allows the code to compile.
As for your last example, I can't get it to break in the way you described.
I'm wondering if someone can help me understand why this program behaves as it does:
fn main() {
let mut x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&mut y);
println!("GOT {}",*y);
}
}
This program compiles under rust 1.35.0 (both 2015 and 2018 editions), and prints
GOT 456
But, I'm confused what's going on here. I'm guessing that this is an example of an auto-dereference. So, in reality, it looks like this:
fn main() {
let mut x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&mut *y);
println!("GOT {}",*y);
}
}
Is that it?
This is a case of deref coercion, but one that is obfuscated by a few other unnecessary parts of the code. The following improvements should be made here:
The mut modifier on variable x is not needed because it is never modified.
The borrow of y in Box::new(&mut y) does not have to be mutable because the variable holds an immutable reference.
The println! implementation also knows to print values behind references, so the explicit * is not needed.
Then, we get the following code:
fn main() {
let x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&y);
println!("GOT {}", y);
}
}
y is a variable of type Box<&i32> which is initially bound to a box created in the outer scope. The subsequent assignment to a new box works because the &y, of type &Box<&i32>, is coerced to &&i32, which can then be put in the box by automatically dereferencing the first borrow. This coercion is required because the variable x can only be assigned values of the same Box<&i32> type.
The lifetime of the reference inside both boxes also ended up being the same, because they refer to the same value in x.
See also:
What is the relation between auto-dereferencing and deref coercion?
Why does this work
#[derive(Debug)]
pub struct Foo<'a,'b> {
s : &'a str,
n : &'b i32
}
#[test]
fn test_struct() {
let f = Foo { s : &"bar" , n : &17 };
println!("{:?}",f);
}
but this doesn't
#[derive(Debug)]
pub enum Bar<'a,'b> {
Baz ( &'a str),
Fub ( &'b i32)
}
#[test]
fn test_struct() {
let b = Bar::Baz(&"Foo");
let c = Bar::Fub(&17);
println!("{:?} {:?}",b,c);
}
The error is (part of a bigger file so ignore line numbers)
src\lib.rs:176:27: 176:29 error: borrowed value does not live long enough
src\lib.rs:176 let c = Bar::Fub(&17);
^~~~~~~~~~~~~~~~~~~~~~
To me it seems like let c = Bar::Fub(&17), the 17 lasts the same life time as the previous line where "Foo" is created on the stack. If I modify it slightly and do
let h = &17;
let c = Bar::Fub(&h);
In which case it's completely clear that h lasts longer than Bar::Fub(). SoI'm not sure how I can can get this to work.
This is a follow up to Lifetime parameters for an enum within a struct
To me it seems like let c = Bar::Fub(&17), the 17 lasts the same life time as the previous line where "Foo" is created on the stack
A string literal always has 'static lifetime and will therefor always live long enough.
I think the issue is that you are hitting is the fact that an enum expression is actually somewhat of a a function call. Somewhat meaning that the lifetime of the argument is ignored in the computation of the Enum's lifetime. The Enum's lifetime apparently is marginally larger, as if you wrote:
let c: Bar;
let x = &17;
c = Bar::Fub(x);
which is already addressed in Scope of addresses: Does not live long enough
In which case it's completely clear that h lasts longer than Bar::Fub().
Yes, the lifetimes are clear here, and it works in the Playpen:
let x = &17;
let c = Bar::Fub(x);
so I'm not sure what you are asking.