Rust/变量与可变性

这是我们学习 Rust 的第二节课, 这节课我会讨论下 Rust 中的变量与常量. 与大多数语言不同, 对于 Rust 来说, 默认情况下变量是不可变的. 这是 Rust 带来的众多优势之一, 它使我们可以利用 Rust 提供的安全性来简化编写多线程代码. 但是, 我们仍然可以选择使变量可变, 所以, 让我们探讨一下 Rust 为什么鼓励我们使用不可变的变量.

不可变变量与可变变量

我们在上个视频中已经创建好了 hello 项目, 如果你还没有完成这一步, 可以回去看我的上一个视频. 我想直接在这个项目上动手脚来演示我们今天的课程, 当然您也可以选择创建一个新的项目, emm, 这一切都很随意啦, 保持学习的乐趣才是最重要的.

我们来创建一个变量, 创建变量必须使用关键字 let. 跟在 let 后面的是变量名, 我们要创建的是 x, 并为 x 赋值为 1.

let x = 1;

你可能会发现我们并未申明 x 的类型, 这可能会让你迷惑, 这是 Rust 的一个特性之一, 叫做自动类型推导. 这里 x 的类型是 i32, 你可以将鼠标移动到变量 x 上, 代码提示插件会弹出类型提示, 这很有用. 所以, 你可能已经猜到了, 如果等号右边是一个字符串, 那么 x 的类型应当是字符串类型.

让我们先专注于眼前的事. 我认为将 x 赋值为 1 并不是一个好的选择, 因为 1 太常见了, 基本上, 你能在任何的在线课程平台和任何课程上都能见到有教师将一个变量赋值为 1, 这无法体现出本门课程的独到之处, 我的目标是带给学生无与伦比的上课体验. 因此, 我决定修改 x 的值, 将之修改为 42.

let x = 1;
x = 42;

我们做一些额外的工作, 将变量 x 打印出来. 你可以看到我使用了一对大括号来做为占位符, 这是在 Rust 中打印某个变量的值的基本方法.

println!("{}", x);

保存, 然后运行这个项目. 我将会看到屏幕中输出 42, 是吗? 但似乎我的狡猾计划出现了一点问题, 我收到了一条错误信息. 我会在这里暂停一段时间, 以便你可以仔细阅读这条错误提示.

我猜时间过去了差不多 30 秒, 你能告诉我错在哪里了吗? 对的, 观看这行提示: "cannot assign twice to immutable variable", 很明确, 我无法为变量两次赋值. 你可能会很沮丧, 因为这种写法在绝大多数语言中都是行得通的, 为什么 Rust 不允许这种操作呢? 我再次提示: 这是 Rust 提供的安全性之一.

有一种很常见的程序错误, 我们的一部分代码会假定某个值是不可变的, 但另一部分代码却修改了这个值. 如果将这两部分代码单独看, 它们都是正确的, 但一旦合并, 则会触发随机的错误, 这种问题真的很令人恼火. 而在 Rust 中, 编译器保证当您声明一个值不会更改时, 它绝对不会被更改. 这意味着在阅读和编写代码时, 我们不必跟踪值的更改方式和位置, 因此, 代码更容易被理解.

但是, 使变量可变仍然很重要, 例如当我们编写一个循环循环 100 次时, 就会需要一个计数器来记录当前已经循环到了第几次. 如果变量总是不可变的, 我很难想象这是一个怎样的灾难. 我们可以在变量前添加关键字 mut 来使变量可变.

因此, Rust 默认情况下变量是不可变的, 除非你显示要求变量可变. 在程序开发过程中, 无论你是否使用的 Rust, 我都会建议你尽量不要多次赋值给一个变量. 我日常工作在编译器上, 我是说, 我的本职工作是和编译器, 虚拟机或类似的东西打交道, 我上面提到的不要给变量多次赋值, 在编译器领域有个专门的名词叫 SSA(Static Single Assignment), 也就是静态单赋值策略. 这种策略很棒, 你应该学习使用这种策略, 无论在任何编程语言中, 它都能使你的代码可读性和可维护性获得极大的提升.

好吧, 我们来给 x 带上 mut. 保存, 然后运行. 编译器不再报错, 这一切都很完美.

常量

无法更改变量的值可能会使您想起大多数其他语言都具有的另一个编程概念: 常量. 与不可变变量一样, 常量也是不允许更改的值, 但是常量和变量之间存在一些差异.

  • 首先, 常量不仅是不可变的, 而且它们始终是不可变的.
  • 常量使用 const 关键字而不是 let 关键字声明常量, 并且必须显示表明类型. 我们将在下一个课程中介绍类型, 所以现在不必担心细节.
  • 常量可以在任何范围内声明, 包括全局范围, 这使它们容易被多次使用.
  • 最后一个区别是, 常量只能设置为常量表达式, 而不能设置为函数调用的结果或只能在运行时计算的任何其他值. 这句话来自 Rust 的官方文档, 但我认为这样的表述并不好, 我会简单的告诉你, 常量在编译期被计算, 而变量在运行期被计算.

最后, 我们定义一个常量 x 替换掉代码中的变量 x:

const x: usize = 42;

现在, 我们已经探讨了变量, 可变性与常量. 本节课程将完美的落幕, 之后, 我们会探讨下变量和常量的数据类型.