fn main() {
type Arr = [i32; 3];
fn get_ref(r: &mut Arr) {}
let mut data = [1, 2, 3];
let data_ref = &mut data;
let data_ref_1 = data_ref;
get_ref(data_ref);
println!("{:?}", data_ref);
}
Compile the above code get the error:
error[E0382]: borrow of moved value: `data_ref`
--> src/main.rs:9:17
|
6 | let data_ref = &mut data;
| -------- move occurs because `data_ref` has type `&mut [i32; 3]`, which does not implement the `Copy` trait
7 | let data_ref_1 = data_ref;
| -------- value moved here
8 |
9 | get_ref(data_ref);
| ^^^^^^^^ value borrowed here after move
error: aborting due to previous error
But, if I add the data_ref_1 type announcement, This code can be compiled successfully:
fn main() {
type Arr = [i32; 3];
fn get_ref(r: &mut Arr) {}
let mut data = [1, 2, 3];
let data_ref = &mut data;
let data_ref_1: &mut Arr = data_ref;
get_ref(data_ref);
println!("{:?}", data_ref);
}
Since variable data_ref is a mutable reference, when it was binded to data_ref_1, it should move to data_ref_1 .
So why the second code can be compiled successfully? Is that affected by NLL?
This is a special coercion (I don't think it has a name1). If you are trying to borrow a unique reference (&mut T), then it will get reborrowed to allow this exact pattern. Note: coercions only apply when the types are already constrained, so it doesn't apply when you infer the type of data_ref_1, but as soon as you add a type annotation, you have constrained the types enough for it to work.
Note: this works too
fn main() {
type Arr = [i32; 3];
fn get_ref(r: &mut Arr) {}
let mut data = [1, 2, 3];
let data_ref = &mut data;
let data_ref_1: &mut _ = data_ref;
get_ref(data_ref);
println!("{:?}", data_ref);
}
1 This isn't deref coercion, it's a special coercion that only applies to references. It's probably similar to unsizing coercion based on this discussion
"Implicit reborrow" is the only term I am aware of.
It does happen at coercion sites, but I don't think it's closely related to (other types of) coercions. It's just a convenience so you don't have to write &mut *data_ref quite as often.
There seems to have been quite a rash of reborrowing-related questions lately, for instance:
You can, but only in that inside-out order. One is borrowing from the other, and non-lexical lifetimes will let that lifetime expire after the last inner use, so the outer can access it again.
What looks like what? I'm not sure I understand. If you mean that assigning something to a variable declared as &mut _ works the same way as passing something to a function taking a &mut _ argument, yes, both are implicit reborrowing.
I think it is worth pointing out that reborrowing acts just like any other kind of mutable borrowing with the lifetime checker — it's just that it automatically happens in some places you might be surprised about.
Mutably borrowing a value will give you a mutable reference into somewhere in that value, and marks the value as unusable in the region described by the lifetime marker on the resulting mutable reference. It's just that the value that is marked unusable here is itself a mutable reference.
In the example before, the _data_ref_1 variable was created by mutably borrowing _data_ref, which meant that _data_ref was unusable while _data_ref_1 was still in use. Just like if _data_ref had been e.g. an integer and we took a mutable reference to the integer. Once _data_ref_1 went away, _data_ref is no longer mutably borrowed, and now usable again like normal.