1.Rust变量
在Rust语言中, 变量默认是不可改变的(immutable), 这是Rust提供给我们的众多优势之一, 让我们可以充分利用Rust提供的安全性和简单并发性来编写代码。
当变量不可变时, 一旦值被绑定在一个名称上, 就不能改变这个值。下面是一段代码的例子:
fn main() {
let x = 1;
println!("The value of x is: {x}");
x = 2;
println!("The value of x is: {x}");
}
这段代码如果是其它高级语言, 看不出有什么问题, 定义了一个变量,先赋值1,然后打印输出, 再将该值赋值2, 再打印该值的内容。
但如果你使用的是支持Rust开发语言的IDE, 在这段代码中会给出一个错误标识, 将鼠标移到上面,会看到一段错误提示,如图:
图片
错误含义就是不可多次为一个不可变的变量赋新值。
如果我们使用Rust自带的编译器进行编译, Rust会很贴心的告诉我们错误在哪个位置, 错误的原因, 错误怎么纠正,如图:
图片
在上图的提示中, Rust编译器建议我们想改变变量的值, 应该在let后面加上mut关键字, 这样变量就可以被改变了。
修改代码如下:
fn main() {
let mut x = 1;
println!("The value of x is: {x}");
x = 2;
println!("The value of x is: {x}");
}
再次编译, 可以看到已经正确打印了变量内容,如图:
图片
2.Rust常量
类似于不可变变量, 常量(constants)是绑定到一个名称的不允许改变的值, 不过常量和变量还是有一定的区别。
首先, 不允许对常量使用mut, 常量不仅默认不可变, 而且总是不可变。声明常量使用const关键字而不是let, 并且必须注明值的类型。
常量可以在任何作用域中声明,包括全局作用域, 这在一个值需要被很多部分的代码用到时很有用。
最后一个区别是,常量只能被设置为常量表达式,而不可以是其它任何只能在运行时计算出的值。
以下是一个常量的声明例子:
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 *3;
常量的名称是 THREE_HOURS_IN_SECONDS,它的值被设置为 60(一分钟内的秒数)乘以 60(一小时内的分钟数)再乘以 3(我们在这个程序中要计算的小时数)的结果。Rust 对常量的命名约定是在单词之间使用全大写加下划线。编译器能够在编译时计算一组有限的操作,这使我们可以选择以更容易理解和验证的方式写出此值,而不是将此常量设置为值 10,800。
在声明它的作用域之中,常量在整个程序生命周期中都有效,此属性使得常量可以作为多处代码使用的全局范围的值,例如一个游戏中所有玩家可以获取的最高分或者光速。
将遍布于应用程序中的硬编码值声明为常量,能帮助后来的代码维护人员了解值的意图。如果将来需要修改硬编码值,也只需修改汇聚于一处的硬编码值。
3.隐藏
在Rust中,我们可以定义一个与之前变量同名的新变量, 在这种情况下, 称之为第一个变量被第二个隐藏(Shadowing)了, 这意味着当我们使用变量的名称时, 编译器将看到第二个变量。实际上,第二个变量“遮蔽”了第一个变量,此时任何使用该变量名的行为中都会视为是在使用第二个变量,直到第二个变量自己也被隐藏或第二个变量的作用域结束。可以用相同变量名称来隐藏一个变量,以及重复使用let关键字来多次隐藏。
看一段下面的代码:
fn main() {
let x = 5;
let x = x + 1;
{
// 进入隐藏作用域
let x = x * 2;
println!("The value of x in the inner scope is: {x}");
}
println!("The value of x is: {x}");
}
我们先在代码下个断点, 通过调试状态观察变量值的情况,如图:
图片
从上图中可以看到, 进入花括号作用域后, x 经过计算已经变成了12, 所以第一个打印的应该是12。
如果出了作用域会怎样呢, 继续单步走一下退出作用域,如图:
图片
可以看到, 出了作用域之后, X的值又变成了6, 因此第二个打印语句的结果就是6。
因此最终输出如下:
图片
隐藏与将变量标记为 mut 是有区别的。当不小心尝试对变量重新赋值时,如果没有使用 let 关键字,就会导致编译时错误。通过使用 let,我们可以用这个值进行一些计算,不过计算完之后变量仍然是不可变的。
mut 与隐藏的另一个区别是,当再次使用 let 时,实际上创建了一个新变量,我们可以改变值的类型,并且复用这个名字。例如,假设程序请求用户输入空格字符来说明希望在文本之间显示多少个空格,接下来我们想将输入存储成数字(多少个空格):
let spaces = " ";
let spaces = spaces.len();
第一个 spaces 变量是字符串类型,第二个 spaces 变量是数字类型。隐藏使我们不必使用不同的名字,如 spaces_str 和 spaces_num;相反,我们可以复用 spaces 这个更简单的名字。然而,如果尝试使用 mut,将会得到一个编译时错误,如下所示:
let mut spaces = " ";
spaces = spaces.len();
错误提示如下:
图片
4.总结
在本篇文章中, 我们学到以下知识点:
- Rust变量定义及可变性、不可变性的灵活应用。
- Rust常量的基本作用域和命名规则。
- Rust变量的隐藏属性规则、原理和应用。