RUST:为什么借用n时我不能分配给'?
Bellow代码创建一个变量n
,然后借入n
并将其命名nref
,然后将新值分配给原始n
。借贷后发生了分配,但一切都很好,并且代码编译。
//example 1
fn main() {
let mut n = 1;
let nref = &n;
n = 3;
}
以下代码还编译。这打印了借用的n
的值。
//example 2
fn main() {
let mut n = 1;
let nref = &n;
println!("{}", nref);
}
如果我使用可变的借用,我什至可以通过nref
更改n
的值。这也编译。
//example 3
fn main() {
let mut n = 1;
let nref = &mut n;
*nref = 4;
println!("{}", n);
}
但是,此代码没有编译:
//example 4
fn main() {
let mut n = 1;
let nref = &n;
n = 3;
println!("{}", nref);
}
它给出了错误:
error[E0506]: cannot assign to `n` because it is borrowed
--> src\main.rs:5:5
|
4 | let nref = &n;
| -- borrow of `n` occurs here
5 | n = 3;
| ^^^^^ assignment to borrowed `n` occurs here
6 | println!("{}", nref);
| ---- borrow later used here
但是在示例1
中,我们还将值分配给了n
借用后,这很好。分配后为什么要使用它引起问题?这要避免什么错误?
如何在示例4
中安全地实现我要做的事情?我只想通过它的参考来读取一个数字的视图,我想更改原始内容,然后我想查看参考,看看该值已更改
edy> edy
再次借用n
。波纹管的作品:
//example 5
fn main() { //line1
let mut n = 1; //line2
let mut nref = &n; //line3
n = 4; //line4
nref = &n; //line5
println!("{}",nref); //line6
}
这是否意味着第4行执行后,第3行的借款不再有效?因此,我必须在第5行上重新借入它,以便可以在第6行上使用它?
这里的引擎盖下发生了什么?我来自C ++背景,因此在我的头上n
存储在存储位置,nref
指向该内存位置。当更改n
的值时,它处于的内存位置不会更改,因此nref
将看到新值。但是,以上表明,当我们将新值分配给n
时,对其的引用不再有效。这是否意味着它的作用更像是Python,其中一切本质上都是一个指向一些内存的指针,当您重新分配某些内容时,您只需在新的内存中重新启动它吗?
The bellow code creates a variable n
, then borrows n
and names it nref
, and then assigns a new value to the original n
. Assignment has happened after a borrow, but all is fine, and the code compiles.
//example 1
fn main() {
let mut n = 1;
let nref = &n;
n = 3;
}
The following code also compiles. This prints the value of the borrowed n
.
//example 2
fn main() {
let mut n = 1;
let nref = &n;
println!("{}", nref);
}
If I use a mutable borrow, I can even change the value of n
via nref
. This also compiles.
//example 3
fn main() {
let mut n = 1;
let nref = &mut n;
*nref = 4;
println!("{}", n);
}
However, this code does not compile:
//example 4
fn main() {
let mut n = 1;
let nref = &n;
n = 3;
println!("{}", nref);
}
It gives the error:
error[E0506]: cannot assign to `n` because it is borrowed
--> src\main.rs:5:5
|
4 | let nref = &n;
| -- borrow of `n` occurs here
5 | n = 3;
| ^^^^^ assignment to borrowed `n` occurs here
6 | println!("{}", nref);
| ---- borrow later used here
But in example 1
, we also assigned a value to n
after it had been borrowed, and it was fine. Why does using it after the assignment cause a problem? What bugs is this trying to avoid?
How can I safely achieve what I am trying to do in example 4
? I want a read only view of a number via it's reference, and I want to change the original, and then I want to look at the reference and see that the value has changed
edit
It seems I have to borrow n
again. The bellow works:
//example 5
fn main() { //line1
let mut n = 1; //line2
let mut nref = &n; //line3
n = 4; //line4
nref = &n; //line5
println!("{}",nref); //line6
}
Does this mean that when line 4 is executed, the borrow from line 3 is no longer valid? And hence I have to re-borrow it on line 5, so that I can use it on line 6?
What is going on under the hood here? I come from a C++ background, so in my head n
is stored at a memory location, and nref
points to that memory location. When the value of n
is changed, the memory location it is at does not change, so nref
will see the new value. However the above suggests that when we assign a new value to n
, the references to it are no longer valid. Does this mean it is acting more like Python, where everything is essentially a pointer to a bit of memory, and when you reassign something, you just repoint it at a new bit of memory?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Let's first explore the technical reason why this example doesn't compile:
Rust allows infinite immutable borrows or one mutable borrow.分配值实际上是可变的借款,因为已经有不变的借入,导致错误,这是不允许的。
但是,这似乎是违反直觉的,因为可能发生的最坏情况是什么?在这种情况下,什么都没有。借贷检查员必须拒绝一些正确的程序才能始终工作。当您开始使代码复杂化时,就会出现问题。如果您使用
VEC
进行堆分配该怎么办?这将是有问题的,因为
vref
现在指向掉落的旧vec
。或者,如果您将nref
发送到另一个线程,并且正在同时读取它,该怎么办?这也会导致有问题的行为。这就是为什么Rust不允许您做这样的事情的原因。您的最后一个案例是Rust编译器的“陷阱”。编译器会自动将借款的寿命缩小到上次使用中,并且由于您从未使用
nref
在重新分配之前,编译器会缩小引用的寿命,这意味着没有冲突:没有冲突:Let's first explore the technical reason why this example doesn't compile:
Rust allows infinite immutable borrows or one mutable borrow. Assigning a value is effectively a mutable borrow, which isn't allowed because there's already an immutable borrow, causing an error.
However, this might seem counter-intuitive, because what's the worst that could happen? In this case, nothing. The borrow-checker has to reject some correct programs in order to always work. The issue arises when you start complicating the code. What if you use a
Vec
for heap allocation instead?This would be problematic because
vref
is now pointing to the oldVec
that got dropped. Or, what if you sentnref
to another thread and were reading it at the same time as writing to it? That would also cause problematic behavior. This is why Rust doesn't allow you to do things like this.Your last case is a "gotcha" by the Rust compiler. The compiler automatically shrinks the lifetime of borrows to the last use, and since you never use
nref
before reassigning it, the compiler shrinks the lifetime of the reference to nothing, meaning there are no conflicts:引用出色的 rust for rustaceans
基本上,当您使用(访问)参考时,借用检查器将在该引用的生命周期内检查回到创建时,并确保在“流”期间没有任何对参考的冲突使用。冲突可能意味着任何破坏Rust的混叠规则的东西:最多可变的参考文献的任何数量不变的参考文献。一旦您做了破坏此规则的事情,原始引用就不再是“活着”,但是
Rustc
在尝试使用使用该引用该参考之前不会丢下错误不再是“活着”。变量名是否在范围中不一定相关。您可能期望借用检查员抱怨的示例,但这并不取决于您不使用使用在发生冲突后的参考文献:没有用法没有冲突。
另外,请注意,寿命是借用的属性,而不是可变名称的。在您的最后一个示例中,您将重新分配到
nref
,用新的Lifetime 创建新的借用。因此,第3行上的原始借款没有冲突,因为您从未使用过该借款。To quote the excellent Rust for Rustaceans
Basically, when you use (access) a reference, the borrow checker will check back through the lifetime of that reference back to when it was created and ensure that at no point during that "flow" a conflicting use of the reference exists. Conflicting can mean anything that breaks Rust's aliasing rules: any number of immutable references xor at most one mutable reference. As soon as you do something that breaks this rule, the original reference is no longer "alive", but
rustc
will not throw an error until you try to use that reference that is no longer "alive". Whether or not the variable name is in scope is not necessarily relevant.Your examples where you might expect the borrow checker to complain, but it doesn't, comes down to the fact that you don't use those references after the conflicting uses: no usage no conflict.
Also, note that the lifetime is a property of the borrow not of the variable name. In your last example, you re-assign to
nref
, creating a new borrow with a new lifetime. Thus, there are no conflicts with the original borrow assigned tonref
on line 3 because you never used that borrow.