在Rust中,"shadowing"和"shadowing"之间有什么区别和“可变性"? [英] In Rust, what's the difference between "shadowing" and "mutability"?

查看:389
本文介绍了在Rust中,"shadowing"和"shadowing"之间有什么区别和“可变性"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Rust第3章中变量和可变性,我们在该主题上进行了两次迭代,以演示Rust中变量的默认,不可变行为:

In Chapter 3 of the Rust Book, Variables and Mutability, we go through a couple iterations on this theme in order to demonstrate the default, immutable behavior of variables in Rust:

fn main() {
    let x = 5;
    println!("The value of x is {}", x);
    x = 6;
    println!("The value of x is {}", x);
}

哪个输出:

error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: make this binding mutable: `mut x`
3 |     println!("The value of x is {}", x);
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

但是,由于Rust使用 shadowing 变量,我们可以简单地执行此操作以更改不可变" x的值:

However, because of Rust's take on shadowing variables, we can simply do this to change the value of the nonetheless "immutable" x:

fn main() {
    let x = 5;
    println!("The value of x is {}", x);
    let x = 6;
    println!("The value of x is {}", x);
}

哪些输出(跳过详细信息):

Which outputs (skipping the details):

The value of x is 5
The value of x is 6

有趣的是,尽管我们没有调用let而是第一次将x绑定到5的事实,该代码也产生了上述两行作为输出: >

Funnily enough, this code also produces the above pair of lines as output, despite the fact that we don't call let but instead mut the first time x is bound to 5:

fn main() {
    let mut x = 5;
    println!("The value of x is {}", x);
    x = 6;
    println!("The value of x is {}", x);
}

这种如何(不是真的)保护变量不被重新分配的模棱两可似乎违背了既定目标,即保护绑定到不可变的值(Rust默认情况下)的变量.在同一章中(还包含 Shadowing 部分):

This ambiguity in how variables are (not really) protected from reassignment seems contrary to the stated goal of protecting the values bound to immutable - by Rust default - variables. From the same chapter (which also contains the section Shadowing):

重要的是,当我们尝试进行编译时会出现编译时错误 更改我们先前指定为不可变的值,因为这 这种情况可能会导致错误.如果我们的代码的一部分在 价值永远不变的假设,以及我们的另一部分 代码更改了该值,代码的第一部分可能 不会做它原本打算做的事情.这种错误的原因可能是 事后很难追查,特别是当第二个 一段代码仅有时会更改值.

It’s important that we get compile-time errors when we attempt to change a value that we previously designated as immutable because this very situation can lead to bugs. If one part of our code operates on the assumption that a value will never change and another part of our code changes that value, it’s possible that the first part of the code won’t do what it was designed to do. The cause of this kind of bug can be difficult to track down after the fact, especially when the second piece of code changes the value only sometimes.

在Rust中,编译器保证在您声明该值时 不会改变,它真的不会改变.这意味着当你 阅读和编写代码,您不必跟踪如何以及 值可能会改变的地方.因此,您的代码更容易推理 通过.

In Rust, the compiler guarantees that when you state that a value won’t change, it really won’t change. That means that when you’re reading and writing code, you don’t have to keep track of how and where a value might change. Your code is thus easier to reason through.

如果我可以通过对let的无辜调用使我的不可变x的这一重要功能回避,为什么我需要mut?有没有一种方法可以使您认真地使x不可变,从而使let x不能重新分配其值?

If I can cause this important feature of my immutable x to be side-stepped with an innocent enough call to let, why do I need mut? Is there some way to really, seriously-you-guys make x immutable, such that no let x can reassign its value?

推荐答案

我相信造成混淆的原因是,您正在将名称与存储空间相混淆.

I believe the confusion is because you're conflating names with storage.

fn main() {
    let x = 5; // x_0
    println!("The value of x is {}", x);
    let x = 6; // x_1
    println!("The value of x is {}", x);
}

在此示例中,有一个名称(x)和两个存储位置(x_0x_1).第二个let只是简单地重新绑定名称x以引用存储位置x_1. x_0的存储位置完全不受影响.

In this example, there is one name (x), and two storage locations (x_0 and x_1). The second let is simply re-binding the name x to refer to storage location x_1. The x_0 storage location is entirely unaffected.

fn main() {
    let mut x = 5; // x_0
    println!("The value of x is {}", x);
    x = 6;
    println!("The value of x is {}", x);
}

在此示例中,有一个名称(x)和一个存储位置(x_0). x = 6分配直接更改存储位置x_0的位.

In this example, there is one name (x), and one storage location (x_0). The x = 6 assignment is directly changing the bits of storage location x_0.

您可能会争辩说它们做同样的事情.如果是这样,那你就错了:

You might argue that these do the same thing. If so, you would be wrong:

fn main() {
    let x = 5; // x_0
    let y = &x; // y_0
    println!("The value of y is {}", y);
    let x = 6; // x_1
    println!("The value of y is {}", y);
}

这将输出:

The value of y is 5
The value of y is 5

这是因为更改x所指向的存储位置绝对不会影响x_0所包含的指针的存储位置x_0.但是,

This is because changing which storage location x refers to has absolutely no effect on the storage location x_0, which is what y_0 contains a pointer to. However,

fn main() {
    let mut x = 5; // x_0
    let y = &x; // y_0
    println!("The value of y is {}", y);
    x = 6;
    println!("The value of y is {}", y);
}

这无法编译,因为您不能在借用x_0时对其进行突变.

This fails to compile because you cannot mutate x_0 while it is borrowed.

Rust十分关心通过参考文献观察到的不必要的突变效应.这与允许阴影没有冲突,因为在阴影时您不会更改值,而只是以一种在其他任何地方都无法观察到的方式更改特定名称的含义.阴影完全是局部变化.

Rust cares about protecting against unwanted mutation effects as observed through references. This doesn't conflict with allowing shadowing, because you're not changing values when you shadow, you're just changing what a particular name means in a way that cannot be observed anywhere else. Shadowing is a strictly local change.

所以是的,您绝对可以避免更改x的值.您不能要做的是保持名称x所指的内容不被更改.最多,您可以使用类似> clippy 之类的东西来拒绝皮棉阴影.

So yes, you absolutely can keep the value of x from being changed. What you can't do is keep what the name x refers to from being changed. At most, you can use something like clippy to deny shadowing as a lint.

这篇关于在Rust中,"shadowing"和"shadowing"之间有什么区别和“可变性"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆