x-i18n: generated_at: “2026-03-01T13:14:54Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: f8e3bd09891f35846d61ec183508fcd4e88ef3450da1107cb6749eeddc815f60 source_path: ch03-01-variables-and-mutability.md workflow: 16
变量与可变性 (Variables and Mutability)
Variables and Mutability
正如在 “使用变量存储值” 部分提到的,默认情况下,变量是不可变的。这是 Rust 给予你的众多暗示之一,旨在让你利用 Rust 提供的安全性和便捷的并发性来编写代码。然而,你仍然可以选择让你的变量变成可变的。让我们探讨一下 Rust 为何以及如何鼓励你优先选择不可变性,以及为什么有时你可能想要选择退出。
As mentioned in the “Storing Values with Variables” section, by default, variables are immutable. This is one of many nudges Rust gives you to write your code in a way that takes advantage of the safety and easy concurrency that Rust offers. However, you still have the option to make your variables mutable. Let’s explore how and why Rust encourages you to favor immutability and why sometimes you might want to opt out.
当变量不可变时,一旦一个值绑定到一个名称,你就不能更改该值。为了说明这一点,请在你的 projects 目录中通过使用 cargo new variables 生成一个名为 variables 的新项目。
When a variable is immutable, once a value is bound to a name, you can’t change that value. To illustrate this, generate a new project called variables in your projects directory by using cargo new variables.
然后,在你新的 variables 目录中,打开 src/main.rs 并将其代码替换为以下代码,这段代码目前还无法编译:
Then, in your new variables directory, open src/main.rs and replace its code with the following code, which won’t compile just yet:
文件名:src/main.rs (Filename: src/main.rs)
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs}}
保存并使用 cargo run 运行程序。你应该会收到一条关于不可变性错误的错误消息,如下输出所示:
Save and run the program using cargo run. You should receive an error message regarding an immutability error, as shown in this output:
{{#include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt}}
这个例子展示了编译器如何帮助你查找程序中的错误。编译器错误可能会让人感到沮丧,但实际上它们只意味着你的程序目前还无法安全地执行你想要它执行的操作;它们并不意味着你不是一个好的程序员!经验丰富的 Rustaceans 仍然会遇到编译器错误。
This example shows how the compiler helps you find errors in your programs. Compiler errors can be frustrating, but really they only mean your program isn’t safely doing what you want it to do yet; they do not mean that you’re not a good programmer! Experienced Rustaceans still get compiler errors.
你收到了错误消息 cannot assign twice to immutable variable `x`,因为你试图为不可变的 x 变量分配第二个值。
You received the error message cannot assign twice to immutable variable `x` because you tried to assign a second value to the immutable x variable.
当我们试图更改被指定为不可变的值时,获得编译时错误非常重要,因为这种情况本身就可能导致 bug。如果代码的一部分基于一个值永远不会改变的假设运行,而代码的另一部分改变了该值,那么代码的第一部分就有可能无法实现其设计功能。这种类型的 bug 的原因事后可能很难追踪,尤其是当第二段代码只是在 有时 更改值时。Rust 编译器保证当你声明一个值不会改变时,它就真的不会改变,所以你不需要自己跟踪它。因此,你的代码更容易推导。
It’s important that we get compile-time errors when we attempt to change a value that’s 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. The Rust compiler guarantees that when you state that a value won’t change, it really won’t change, so you don’t have to keep track of it yourself. Your code is thus easier to reason through.
但可变性可能非常有用,并且可以使代码编写起来更加方便。虽然变量默认是不可变的,但你可以通过在变量名前添加 mut 来使其变为可变,就像你在 第 2 章 中所做的那样。添加 mut 还能向未来的代码读者传达意图,表明代码的其他部分将会更改此变量的值。
But mutability can be very useful and can make code more convenient to write. Although variables are immutable by default, you can make them mutable by adding mut in front of the variable name as you did in Chapter 2. Adding mut also conveys intent to future readers of the code by indicating that other parts of the code will be changing this variable’s value.
例如,让我们将 src/main.rs 更改为以下内容:
For example, let’s change src/main.rs to the following:
文件名:src/main.rs (Filename: src/main.rs)
#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-02-adding-mut/src/main.rs}}
}
现在运行程序,我们得到:
When we run the program now, we get this:
{{#include ../listings/ch03-common-programming-concepts/no-listing-02-adding-mut/output.txt}}
当使用 mut 时,我们被允许将绑定到 x 的值从 5 更改为 6。最终,决定是否使用可变性取决于你,取决于你认为在特定情况下什么最清晰。
We’re allowed to change the value bound to x from 5 to 6 when mut is used. Ultimately, deciding whether to use mutability or not is up to you and depends on what you think is clearest in that particular situation.
声明常量 (Declaring Constants)
Declaring Constants
与不可变变量类似,常量 (constants) 是绑定到一个名称且不允许更改的值,但常量和变量之间有一些区别。
Like immutable variables, constants are values that are bound to a name and are not allowed to change, but there are a few differences between constants and variables.
首先,你不被允许对常量使用 mut。常量不仅默认不可变——它们始终不可变。你使用 const 关键字而不是 let 关键字来声明常量,并且值的大小 必须 标注类型。我们将在下一节 “数据类型” 中介绍类型和类型标注,所以现在不用担心细节。只要知道你必须始终标注类型即可。
First, you aren’t allowed to use mut with constants. Constants aren’t just immutable by default—they’re always immutable. You declare constants using the const keyword instead of the let keyword, and the type of the value must be annotated. We’ll cover types and type annotations in the next section, “Data Types”, so don’t worry about the details right now. Just know that you must always annotate the type.
常量可以在任何作用域中声明,包括全局作用域,这使得它们对于代码中许多部分都需要了解的值非常有用。
Constants can be declared in any scope, including the global scope, which makes them useful for values that many parts of code need to know about.
最后一个区别是,常量只能设置为常量表达式,而不能设置为只能在运行时计算的值的结果。
The last difference is that constants may be set only to a constant expression, not the result of a value that could only be computed at runtime.
这是一个常量声明的例子:
Here’s an example of a constant declaration:
#![allow(unused)]
fn main() {
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
}
常量的名称是 THREE_HOURS_IN_SECONDS,它的值被设置为 60(一分钟的秒数)乘以 60(一小时的分钟数)再乘以 3(我们在这个程序中想要计算的小时数)的结果。Rust 对常量的命名约定是使用全大写字母,并在单词之间使用下划线。编译器能够在编译时评估有限的一组操作,这让我们可以选择以一种更容易理解和验证的方式写出这个值,而不是将这个常量设置为值 10,800。有关声明常量时可以使用哪些操作的更多信息,请参阅 Rust 参考手册中关于常量求值的部分。
The constant’s name is THREE_HOURS_IN_SECONDS, and its value is set to the result of multiplying 60 (the number of seconds in a minute) by 60 (the number of minutes in an hour) by 3 (the number of hours we want to count in this program). Rust’s naming convention for constants is to use all uppercase with underscores between words. The compiler is able to evaluate a limited set of operations at compile time, which lets us choose to write out this value in a way that’s easier to understand and verify, rather than setting this constant to the value 10,800. See the Rust Reference’s section on constant evaluation for more information on what operations can be used when declaring constants.
常量在程序运行的整个时间内都有效,且在声明它们的作用域内。这一特性使得常量对于应用程序域中程序多个部分可能需要知道的值非常有用,例如游戏允许任何玩家获得的最大积分数,或光速。
Constants are valid for the entire time a program runs, within the scope in which they were declared. This property makes constants useful for values in your application domain that multiple parts of the program might need to know about, such as the maximum number of points any player of a game is allowed to earn, or the speed of light.
将程序中各处使用的硬编码值命名为常量,有助于向未来的代码维护者传达该值的含义。如果在将来需要更新硬编码值,这也有助于在代码中只需更改一处地方。
Naming hardcoded values used throughout your program as constants is useful in conveying the meaning of that value to future maintainers of the code. It also helps to have only one place in your code that you would need to change if the hardcoded value needed to be updated in the future.
重影 (Shadowing)
Shadowing
正如你在 第 2 章 的猜数字游戏教程中所看到的,你可以声明一个与之前的变量同名的新变量。Rustaceans 说第一个变量被第二个变量 重影 (shadowed) 了,这意味着当你使用变量名称时,编译器看到的是第二个变量。实际上,第二个变量遮蔽了第一个变量,将所有对变量名的使用都据为己有,直到它自己被重影或作用域结束。我们可以通过使用相同的变量名并重复使用 let 关键字来重影一个变量,如下所示:
As you saw in the guessing game tutorial in Chapter 2, you can declare a new variable with the same name as a previous variable. Rustaceans say that the first variable is shadowed by the second, which means that the second variable is what the compiler will see when you use the name of the variable. In effect, the second variable overshadows the first, taking any uses of the variable name to itself until either it itself is shadowed or the scope ends. We can shadow a variable by using the same variable’s name and repeating the use of the let keyword as follows:
文件名:src/main.rs (Filename: src/main.rs)
#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-03-shadowing/src/main.rs}}
}
这个程序首先将 x 绑定到值 5。然后,它通过重复 let x = 创建一个新变量 x,获取原始值并加上 1,使得 x 的值为 6。接着,在由花括号创建的内部作用域中,第三个 let 语句也重影了 x 并创建了一个新变量,将之前的值乘以 2,使 x 的值为 12。当该作用域结束时,内部重影结束,x 回到 6。当我们运行这个程序时,它将输出以下内容:
This program first binds x to a value of 5. Then, it creates a new variable x by repeating let x =, taking the original value and adding 1 so that the value of x is 6. Then, within an inner scope created with the curly brackets, the third let statement also shadows x and creates a new variable, multiplying the previous value by 2 to give x a value of 12. When that scope is over, the inner shadowing ends and x returns to being 6. When we run this program, it will output the following:
{{#include ../listings/ch03-common-programming-concepts/no-listing-03-shadowing/output.txt}}
重影与将变量标记为 mut 不同,因为如果我们不小心尝试在不使用 let 关键字的情况下重新分配给此变量,我们将得到编译时错误。通过使用 let,我们可以对一个值执行一些变换,但在这些变换完成后使变量保持不可变。
Shadowing is different from marking a variable as mut because we’ll get a compile-time error if we accidentally try to reassign to this variable without using the let keyword. By using let, we can perform a few transformations on a value but have the variable be immutable after those transformations have completed.
mut 和重影之间的另一个区别是,因为当我们再次使用 let 关键字时实际上是在创建一个新变量,所以我们可以更改值的类型但重用相同的名称。例如,假设我们的程序要求用户通过输入空格字符来显示他们希望文本之间有多少个空格,然后我们想要将该输入存储为一个数字:
The other difference between mut and shadowing is that because we’re effectively creating a new variable when we use the let keyword again, we can change the type of the value but reuse the same name. For example, say our program asks a user to show how many spaces they want between some text by inputting space characters, and then we want to store that input as a number:
#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-04-shadowing-can-change-types/src/main.rs:here}}
}
第一个 spaces 变量是字符串类型,第二个 spaces 变量是数字类型。因此,重影让我们免于想出不同的名称,例如 spaces_str 和 spaces_num;相反,我们可以重用更简单的 spaces 名称。但是,如果我们尝试为此使用 mut,如下所示,我们将得到编译时错误:
The first spaces variable is a string type, and the second spaces variable is a number type. Shadowing thus spares us from having to come up with different names, such as spaces_str and spaces_num; instead, we can reuse the simpler spaces name. However, if we try to use mut for this, as shown here, we’ll get a compile-time error:
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/src/main.rs:here}}
错误提示说我们不被允许更改变量的类型:
The error says we’re not allowed to mutate a variable’s type:
{{#include ../listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt}}
现在我们已经探索了变量的工作原理,让我们看看它们可以拥有的更多数据类型。
Now that we’ve explored how variables work, let’s look at more data types they can have.