3.1 变量与可变性
3.1.0. 写在正文之前
欢迎来到Rust自学的第三章,一共有6个小节,分别是:
- 变量与可变性(本文)
- 数据类型:标量类型
- 数据类型:复合类型
- 函数和注释
- 控制流:
if else - 控制流:循环
通过第二章的小游戏(没看的初学者强烈建议看一下),相信你已经学会了基本的Rust语法,而在第三章我们将更深一层,了解Rust中的通用的编程概念。
3.1.1. 可变/不可变变量的声明
-
声明变量使用
let关键字。 -
默认情况下,变量是不可变的。以下是错误例:
fn main(){
let machine = 6657;
machine = 0721;
println!("machine is {}", machine);
}
Output:
error[E0384]: cannot assign twice to immutable variable `machine`
--> src/main.rs:3:2
|
2 | let machine = 6657;
| ------- first assignment to `machine`
3 | machine = 0721;
| ^^^^^^^^^^^^^^ cannot assign twice to immutable variable
|
help: consider making this binding mutable
|
2 | let mut machine = 6657;
| +++
- 在
let后加上mut才能声明可变变量。以下是成功例,输出内容在注释里:
fn main(){
let mut machine = 6657;
machine = 721;
println!("machine is {}", machine); // Output: machine is 721
}
3.1.2. 变量与常量
有很多人在刚开始学Rust的时候都会搞不清不可变变量与常量的区别在哪里。常量在绑定值后也是不可变的,但它与不可变变量有几处重要区别:
- 常量不能使用
mut,一旦声明就不可变。 - 声明常量需要使用
const关键字,并且必须显式标注类型;不可变变量不必显式标注。 - 常量可以在任何作用域内声明,包括全局作用域。
- 常量只能绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才能计算出的值。
- 在程序运行期间,常量在其声明的作用域中一直有效。
- 命名规范:Rust里常量使用全大写字母,每个单词之间用下划线分开,例如:
MAX_POINTS。
常量声明的例子:
const WJQ: i32 = 66570721;
fn main(){
const WJQ_MACHINE: u32 = 6_657;
let mut machine = 6657;
machine = 721;
println!("machine is {}", machine); // Output: machine is 721
println!("WJQ is {}", WJQ); // Output: WJQ is 66570721
println!("WJQ_MACHINE is {}", WJQ_MACHINE); // Output: WJQ_MACHINE is 6657
}
其中的i32、u32是其类型。Rust支持插入下划线增强可读性,这个例子中的6_657写成6657也是可以的。
这个常量既可以在全局声明,也可以声明在main函数里,也可以在其他作用域中。
3.1.3. 遮蔽(Shadowing)
在 2.3 猜数游戏Pt.3 输入数与随机数的对比 中声明变量时就提过一嘴,Rust允许使用同名新变量来遮蔽原来的变量,这叫做遮蔽(当一个名称在当前作用域中被重新定义时,会隐藏外部作用域中同名的变量、函数或类型)。每次遮蔽时,原变量的值和类型都会被新变量替代。它允许代码复用同一个变量名,而无需再声明一个全新的变量。
这里可以举一个例子:
fn main(){
let a = 1;
println!("{}", a);
let a = "one";
println!("{}", a);
}
这么做程序不会报错,并且打印出了:
1
one
当程序执行 let a = 1; 时,a被绑定为1,所以打印出的是1;之后执行 let a = "one"; 时,程序注意到a被复用了,就会抛弃原来的值1,把a绑定为"one",所以下一行打印的就是one。这就是遮蔽。
要注意的是,使用遮蔽和把变量声明为可变变量是有不同之处的:
- 在遮蔽中,使用
let声明的新变量依然是不可变变量。 - 在遮蔽中,使用
let声明的同名新变量的类型可以与之前不同。
fn main(){
let machine = "wjq";
let machine = 6657;
println!("{}", machine);
}
上边这个程序使用了遮蔽,不会报错。第二次 let machine = 6657; 是新声明的变量,与之前的 machine 并没有关系。
fn main(){
let mut machine = "wjq";
machine = 6657;
println!("{}", machine);
}
Output:
error[E0308]: mismatched types
--> src/main.rs:3:15
|
2 | let mut machine = "wjq";
| ----- expected due to this value
3 | machine = 6657;
| ^^^^ expected `&str`, found integer
上边这个程序使用了可变变量。Rust 是强类型语言,变量的类型在首次声明时确定。 赋值 machine = 6657 试图将一个整数赋值给一个字符串类型变量,类型不匹配,编译器会报 expected &str, found integer。