Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3.1 变量与可变性

3.1.0. 写在正文之前

欢迎来到Rust自学的第三章,一共有6个小节,分别是:

通过第二章的小游戏(没看的初学者强烈建议看一下),相信你已经学会了基本的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
}

其中的i32u32是其类型。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