Env: rustc 1.82.0 (f6e511eec 2024-10-15)
Question: Dereferencing vs. Direct Borrowing in Rust
I’m confused about the difference between *&T
and T
in borrowing. The following code compiles with let b = &mut *a
, but fails with let b = &mut x
. Why does *a
behave differently from x
in this context?
Additionally, uncommenting the last line (*b = ...
) causes the error:
cannot assign to
*a
because it is borrowed
fn annoying_borrow() {
let mut x = Box::new(1);
let a = &mut x;
let b = &mut *a;
// let b = &mut x; // error: cannot borrow `x` as mutable more than once at a time
*a = Box::new(2);
// *b = Box::new(3); // error: `*a` is assigned to here but it was already borrowed
}
Does using the *a
instead of the x
here further imply the subtle difference between them? Emmm, what I really want to explore is not the difference between *a
and x
, but the rules of borrowing in the Rust type system (compiler).
Background:
I’ve referenced Programming Rust, 2nd Ed. (Chapter 5), but I cannot fully comprehend this knowledge:
Shared access is read-only access.
Values borrowed by shared references are read-only. Across the lifetime of a shared reference, neither its referent, nor anything reachable from that referent, can be changed by anything. There exist no live mutable references to anything in that structure, its owner is held read-only, and so on. It’s really frozen.
Mutable access is exclusive access.
A value borrowed by a mutable reference is reachable exclusively via that reference. Across the lifetime of a mutable reference, there is no other usable path to its referent or to any value reachable from there. The only references whose lifetimes may overlap with a mutable reference are those you borrow from the mutable reference itself.
I wonder if there is any unified and detailed explanation of borrowing in Rust. Perhaps there used to be a clear set of rules about borrowing in Rust, but with the compiler continuously relaxing syntax restrictions (to facilitate coding in certain scenarios?), the current rules are more chaotic?
Env: rustc 1.82.0 (f6e511eec 2024-10-15)
Question: Dereferencing vs. Direct Borrowing in Rust
I’m confused about the difference between *&T
and T
in borrowing. The following code compiles with let b = &mut *a
, but fails with let b = &mut x
. Why does *a
behave differently from x
in this context?
Additionally, uncommenting the last line (*b = ...
) causes the error:
cannot assign to
*a
because it is borrowed
fn annoying_borrow() {
let mut x = Box::new(1);
let a = &mut x;
let b = &mut *a;
// let b = &mut x; // error: cannot borrow `x` as mutable more than once at a time
*a = Box::new(2);
// *b = Box::new(3); // error: `*a` is assigned to here but it was already borrowed
}
Does using the *a
instead of the x
here further imply the subtle difference between them? Emmm, what I really want to explore is not the difference between *a
and x
, but the rules of borrowing in the Rust type system (compiler).
Background:
I’ve referenced Programming Rust, 2nd Ed. (Chapter 5), but I cannot fully comprehend this knowledge:
Shared access is read-only access.
Values borrowed by shared references are read-only. Across the lifetime of a shared reference, neither its referent, nor anything reachable from that referent, can be changed by anything. There exist no live mutable references to anything in that structure, its owner is held read-only, and so on. It’s really frozen.
Mutable access is exclusive access.
A value borrowed by a mutable reference is reachable exclusively via that reference. Across the lifetime of a mutable reference, there is no other usable path to its referent or to any value reachable from there. The only references whose lifetimes may overlap with a mutable reference are those you borrow from the mutable reference itself.
I wonder if there is any unified and detailed explanation of borrowing in Rust. Perhaps there used to be a clear set of rules about borrowing in Rust, but with the compiler continuously relaxing syntax restrictions (to facilitate coding in certain scenarios?), the current rules are more chaotic?
Share Improve this question edited Mar 6 at 13:38 galaxyzen asked Mar 6 at 11:06 galaxyzengalaxyzen 133 bronze badges 7 | Show 2 more comments1 Answer
Reset to default 1Mutable references can be 'inactive'. Only one mutable reference can be actively holding exclusive mutable access, but just because a reference exists, does not mean it holds access. When you borrow through a mutable reference, that access is transferred to the borrowing reference.
This means that you can create a mutable reference b through the mutable reference a that has access, transferring the access from a to b, until b is dropped when it is reverted to a. You can not use a directly whilst b exists, because it does not have access, like how x does not have access whilst a exists.
Additionally you can create a shared reference from a mutable reference, in which case, the mutable references access is downgraded to shared until the last reference borrowed from it is dropped.
let b = &mut *a
is borrowinga
, notx
(which is still borrowed only bya
). – Jmb Commented Mar 6 at 13:09*
? I can't understand the "is borrowinga
, notx
", isn't*a
andx
essentially the same thing? – galaxyzen Commented Mar 6 at 13:42*a
andx
are equivalent. From the point of view of the borrow checker&*a
borrows froma
, which is fine (but makesa
temporarily inaccessible while the new borrow is in effect), whereas&x
borrows fromx
, which results in multiple simultaneous borrows (sincea
is still in scope at that point and also borrows fromx
). – Jmb Commented Mar 6 at 14:40a
with the value that equals to the address ofx
in the stack frame? This view lingers in my mind:&*a
=>&(*a)
=>&x
– galaxyzen Commented Mar 6 at 14:48