Rust 学习笔记 - 变量与可变性

| 笔记 | 2220 | 6分钟 | Rust学习笔记

本文属于学习笔记,内容可能有误、可能不全面,仅代表个人在学习这一特性时的理解和总结

开始学习Rust。这是第一篇学习笔记,记录一些基础的概念。

1 Rust 变量与可变性

1.1 常量

Rust中的常量与其他语言类似,使用 const 声明,命名规范为所有字母大写,用下划线分割

常量声明时,必须指定类型必须赋初值。并且初值只能是常量表达式,不能是函数的调用结果、或是运行过程中计算得到的值。

const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

1.2 变量

Rust中的变量使用 let 声明,可以自动推导类别,也可以使用 : 指定类别。

变量又分为:可变变量不可变变量let 声明的默认是不可变变量,在变量前加上 mut 才是可变变量。

1.2.1 可变变量

可变变量的使用方法是符合在其他编程语言里使用习惯的写法,直接使用 = 进行赋值,变量的类型无法更改。

fn main() {
    let mut x = 5;
    x = 6; // 正确
    x = "abc"; // 改变了类型,错误
}

1.2.2 不可变变量 & Shadow

顾名思义,不可变变量无法直接复制修改:

fn main() {
    let x = 5;
    x = 6; // 错误 
}
error[E0384]: cannot assign twice to immutable variable `x`
 --> test.rs:3:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: consider making this binding mutable: `mut x`
3 |     x = 6; // 错误 
  |     ^^^^^ cannot assign twice to immutable variable

error: aborting due to 1 previous error; 2 warnings emitted

传统的方法在Rust里变得复杂了,说明Rust一定提出了一个更好的特性——Shadow

Rust允许使用 let 创建同名变量,例如:

fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    let x = 6;
    println!("The value of x is: {}", x);
    let x = x * 2;
    println!("The value of x is: {}", x);
    let x = "hello";
    println!("The value of x is: {}", x);
}

结果是:

The value of x is: 5
The value of x is: 6
The value of x is: 12
The value of x is: hello

并不像其他编程语言里,定义同名变量通常会报错。Rust直接使用后定义的变量覆盖之前定义的变量。因为这是重新定义变量,所以甚至可以改变变量的类型。

这个过程被取了一个好听的名字 Shadow,新变量像把旧变量罩住了、盖住了一样。

这个特性最好用的地方就在于可以改变变量的类型

在其他语言中经常有以下情况,在类型转换前后需要定义两个不同名称的变量,实际上他们表达的含义是完全相同的。

int main() {
	char score_str[] = "123";
    int score = atoi(score_str);
}

使用 Rust 可以解决这个问题:

fn main() {
    let score = "123";
    let score: i32 = score.parse().unwrap();
}

即保证了变量的强类型安全性,又保留了使用的便捷性。很优雅。

还有一个情景 shadow 很好用。假如我在写一个很复杂的数学公式,公式的好几个部分都用到了同样的符号 a

fn main() {
	let a = 3;
    let b = a + 1 ... 
    // 此处省略一大堆内容
    
    // 在里上面的a隔了好多行的地方,我又想定义一个变量a
    // 我可以当作之前从来没有使用过那个变量a一样,直接定义一个新的a
    let a = 4;
    // 在后续的代码中,我也会很自然的认为a就是我最近定义的a = 4
    // 而不会是之前的 a = 3
}

另外,shadow 可变变量会报 warning:

fn main() {
    let mut score = "123";
    let score: i32 = score.parse().unwrap();
    println!("score: {}", score);
}
warning: variable does not need to be mutable
 --> test.rs:2:9
  |
2 |     let mut score = "123";
  |         ----^^^^^
  |         |
  |         help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` on by default

warning: 1 warning emitted

score: 123

因为这样写语法上没问题,但是这样就改变了使用 mut 的本意。

我的理解是:

  • 如果需要使用的变量是传统意义的变量,也就是其他编程语言中最常用的变量,使用 let mut 声明可变变量。
  • 不可变变量的 shadow 就是用来解决无用中间变量过多的问题。生命周期短的变量,都可以使用不可变变量,因为他们通常不会被修改,并且影响的范围很小。解决了一个变量名焦虑的问题。