Rust 中的变量和可变性是编程的基础概念。默认情况下,变量是不可变的,这意味着一旦你给变量赋值,就不能改变其值。
一、变量定义及规则
- 变量的定义
- 在 Rust 中,变量是用来存储数据的命名容器。我们可以使用
let
关键字来声明一个变量。 - 变量声明的基本语法是:
let 变量名: 数据类型 = 值;
例如:
rust
fn main() {
let age: i32 = 30; // 声明一个整型变量,类型为 i32,值为 30
println!("My age is: {}", age);
}
注意:在 Rust 中,所有变量在使用前必须明确其类型。不过,Rust 编译器具有强大的类型推导能力,在大多数情况下,我们可以省略类型注解,编译器会自动推断出变量的类型。
例如:
rust
fn main() {
let age = 30; // 省略类型注解,编译器会推导出 age 的类型为 i32
println!("My age is: {}", age);
}
- 变量的命名规则
- 变量名必须以字母或下划线
_
开头,后续字符可以是字母、数字或下划线。 - 变量名是区分大小写的,例如
age
和Age
是两个不同的变量。 - 避免使用 Rust 的关键字作为变量名,如
let
、fn
等。如果确实需要使用这些关键字作为变量名,可以在前面加上r#
前缀,例如r#let
。
二、变量的可变性
- 默认不可变性
- Rust 中的变量默认是不可变的,这意味着一旦给变量绑定了值,就不能再改变这个值。这种设计有助于提高代码的安全性和并发性,防止意外修改变量导致的错误。
例如:
rust
fn main() {
let x = 5;
println!("The value of x is: {}", x);
// error[E0384]: cannot assign twice to immutable variable `x`
// x = 10; // 错误!不能对不可变变量 x 重新赋值
运行上面的代码会导致编译错误。
- 声明可变变量
- 如果需要在程序运行过程中修改变量的值,可以使用
mut
关键字来声明一个可变变量。 - 例如:
rust
fn main() {
let mut x = 5; // 声明一个可变变量 x
println!("The value of x is: {}", x);
x = 10; // 现在可以修改 x 的值
println!("The new value of x is: {}", x);
}
- 输出结果:
The value of x is: 5
The new value of x is: 10
三、变量的作用域和生命周期
-
作用域
- 变量的作用域是指变量在程序中有效的范围。Rust 中的变量作用域由其声明位置决定,从声明开始,到包含它的代码块(如函数、循环或条件语句)的末尾结束。
- 例如:
rustfn main() { let x = 5; // x 的作用域从声明开始,到 main 函数的末尾结束 { let y = 10; // y 的作用域仅限于这个大括号内 println!("The value of y is: {}", y); } // y 的作用域结束,y 变量被销毁 println!("The value of x is: {}", x); // x 仍然有效 }
大括号
{}
:在 Rust 中,大括号通常用来定义代码块,如函数体、循环体、条件语句的分支等。
每个由大括号包围的代码块都创建了一个新的作用域。
-
生命周期
- 变量的生命周期与其作用域密切相关。一旦变量超出其作用域,该变量就会被销毁,其所占用的内存也会被释放。
- Rust 的所有权系统确保了在变量生命周期结束时,其占用的资源能够被正确地释放,从而避免了内存泄漏等问题。
四、常量的定义和使用
-
常量的定义
- 常量是一种特殊的变量,其值在编译时就已确定,并且在程序运行期间不能改变。
- 使用
const
关键字来声明常量,并且必须显式指定其类型。 - 例如:
rust
fn main() {
const PI: f64 = 3.141592653589793; // 声明一个常量 PI,类型为 f64
println!("The value of PI is: {}", PI);
}
-
常量的特性
- 常量名通常使用全大写字母和下划线(如
MAX_SIZE
),以区别于变量名。 - 常量可以在任何作用域中声明,包括全局作用域。一旦声明,常量在其作用域内始终有效。
- 常量的值必须是编译时常量表达式,不能是函数调用的结果或运行时才能确定的值。
- 常量名通常使用全大写字母和下划线(如
五、变量的遮蔽(Shadowing)
-
遮蔽的概念
- 在 Rust 中,可以在同一作用域或嵌套作用域内使用相同的变量名重新声明一个变量。新的变量会“遮蔽”(Shadow)之前声明的同名变量,使得在遮蔽期间,同名变量引用的是新声明的变量。
- 遮蔽机制允许在不改变原始变量的情况下,对变量进行重新绑定或类型转换。
-
遮蔽的示例
rust
fn main() {
let x = 5;
println!("The value of x is: {}", x); // 输出 5
let x = x + 1; // 重新声明变量 x,遮蔽了之前的 x
println!("The new value of x is: {}", x); // 输出 6
{
let x = x * 2; // 在内部作用域中再次遮蔽 x
println!("The value of x in the inner scope is: {}", x); // 输出 12
}
println!("The value of x is: {}", x); // 输出 6,外部作用域的 x 重新可见
}
- 在这个示例中,
x
被遮蔽了两次,每次遮蔽都创建了一个新的变量x
,其作用域仅限于声明它的代码块内。
六、变量遮蔽与可变性的区别
rust
let spaces = " ";
let spaces = spaces.len();
如上例, 变量遮蔽是指在同一个作用域内,使用相同的变量名重新声明一个新的变量,新的变量会“遮蔽”之前声明的同名变量。在遮蔽之后,程序中对该变量名的引用将指向新的变量。
遮蔽允许在重新声明时改变变量的类型。例如,可以先声明一个整数类型的变量,然后在同一作用域内使用相同的变量名声明一个字符串类型的变量。
可变性是指变量在声明后,其值是否可以被修改, 但是类型不可修改。
例如:下列代码会编译报错
rust
let mut spaces = " ";
// error[E0308]: mismatched types
// ^^^^^^^^^^^^ expected `&str`, found `usize`
spaces = spaces.len();
七、总结
Rust 中的变量和可变性是编程的基础。通过 let
关键字声明变量,使用 mut
关键字声明可变变量。
变量默认是不可变的,这有助于提高代码的安全性和并发性。
常量使用 const
关键字声明,其值在编译时就已确定,并且在程序运行期间不能改变。
遮蔽机制允许在不改变原始变量的情况下,对变量进行重新绑定或类型转换。