rust学习笔记之基础:变量及可变性、常量
变量和可变性
变量绑定
Rust 通过静态类型确保类型安全。变量绑定可以在声明时说明类型,不过在多数情况下,编译器能够从上下文推导出变量的类型,从而大大减少了类型说明的工作。
使用 let 绑定操作可以将值(比如字面量)绑定(bind)到变量。
fn main() {
let an_integer = 1u32;
let a_boolean = true;
let unit = ();
let copied_integer = an_integer;
println!("An integer: {:?}", copied_integer);
println!("A boolean: {:?}", a_boolean);
println!("Meet the unit value: {:?}", unit);
}
可变变量
变量绑定默认是不可变的(immutable),当尝试改变一个前面指定为不可变的值时会得到编译错误。但加上 mut 修饰语后变量就可以改变。
fn main() {
let x = 5; //不可变
let mut y = 1; //可变
}
作用域和遮蔽
变量绑定有一个作用域(scope),它被限定只在一个代码块(block)中生存(live)。 代码块是一个被 {} 包围的语句集合。
另外也允许变量遮蔽(variable shadowing)。可以声明和前面变量具有相同名称的新变量,称这种行为是第一个变量被第二个变量遮蔽(shadow),这意味着当我们使用变量时我们看到的会是第二个变量的值。
fn main() {
// 此绑定生存于 main 函数中
let long_lived_binding = 1;
// 这是一个代码块,比 main 函数拥有更小的作用域
{
// 此绑定只存在于本代码块
let short_lived_binding = 2;
println!("inner short: {}", short_lived_binding);
// 此绑定*遮蔽*了外面的绑定
let long_lived_binding = 5_f32;
println!("inner long: {}", long_lived_binding);
}
// 代码块结束
// 报错!`short_lived_binding` 在此作用域上不存在
// println!("outer short: {}", short_lived_binding);
println!("outer long: {}", long_lived_binding);
// 此绑定同样*遮蔽*了前面的绑定
let long_lived_binding = 'a';
println!("outer long: {}", long_lived_binding);
}
输出
inner short: 2
inner long: 5
outer long: 1
outer long: a
变量遮蔽和将变量标记为 mut 的方式的区别:
- 除非我们再次使用 let 关键字,否则若是我们不小心尝试重新赋值给这个变量,我们将得到一个编译错误。通过使用 let,我们可以对一个值进行一些转换,但在这些转换完成后,变量将是不可变的。
- mut 和变量遮蔽之间的另一个区别是,因为我们在再次使用 let 关键字时有效地创建了一个新的变量,所以我们可以改变值的类型,但重复使用相同的名称。
变量先声明
可以先声明(declare)变量绑定,后面才将它们初始化(initialize)。但是这种做法很 少用,因为这样可能导致使用未初始化的变量。
fn main() {
let a_binding;// 声明一个变量绑定
{
let x = 2;
a_binding = x * x;// 初始化一个绑定
}
println!("a binding: {}", a_binding);
let another_binding;
// 报错!使用了未初始化的绑定
// println!("another binding: {}", another_binding);
another_binding = 1;
println!("another binding: {}", another_binding);
}
输出
a binding: 4
another binding: 1
编译器禁止使用未经初始化的变量,因为这会产生未定义行为(undefined behavior)。
冻结
当数据被相同的名称不变地绑定时,它还会冻结(freeze)。在不可变绑定超出作用域之前,无法修改已冻结的数据:
fn main() {
let mut _mutable_integer = 7i32;
{
let _mutable_integer = _mutable_integer;// 被不可变的 `_mutable_integer` 遮蔽
// _mutable_integer = 50;// 报错!`_mutable_integer` 在本作用域被冻结
// `_mutable_integer` 离开作用域
}
// 正常运行! `_mutable_integer` 在这个作用域没有冻结
_mutable_integer = 3;
}
常量
常量(constant)是绑定到一个常量名且不允许更改的值。常量不仅仅默认不可变,而且自始至终不可变。常量常常使用 const 关键字来声明,并且值的类型必须注明。Rust 常量的命名约定是全部字母都使用大写,并使用下划线分隔单词。
Rust 有两种常量,可以在任意作用域声明,包括全局作用域。它们都需要显式的类型声明:
- const:不可改变的值(通常使用这种)。
- static:具有
'static生命周期的,可以是可变的变量(须使用 static mut 关键字)。
有个特例就是 "string" 字面量。它可以不经改动就被赋给一个 static 变量,因为它的类型标记:&'static str 就包含了所要求的生命周期 'static。其他的引用类型都必须特地声明,使之拥有'static 生命周期。这两种引用类型的差异似乎也无关紧要,因为无论如何,static 变量都得显式地声明。
// 全局变量是在在所有其他作用域之外声明的。
static LANGUAGE: &'static str = "Rust";
const THRESHOLD: i32 = 10;
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
fn is_big(n: i32) -> bool {
// 在一般函数中访问常量
n > THRESHOLD
}
fn main() {
let n = 16;
println!("This is {}", LANGUAGE);
println!("The threshold is {}", THRESHOLD);
println!("{} is {}", n, if is_big(n) { "big" } else { "small" });
}
浙公网安备 33010602011771号