变量与可变性
在Rust中,初特殊声明外,默认情况下的变量是不可变的immutable
,这一特征让你充分利用 Rust 提供的安全性和简单并发性的方式来编写代码。不过你也可以选择让变量是可变的mutable
。不可变变量意味着一旦声明后值就不能改变,如果尝试改变会发生什么,接下来尝试用下面的代码来分析。
fn main(){
let x = 0;
println!("x:{}",x)
x = 10;
println!("x:{}",x)
}
通过运行上述代码,将收到编译器的报错,因为在第二行第一次声明该变量时,并未标识其为可变。具体原因为:cannot assign twice to immutable variable
x(不能对不可变变量二次赋值)
.而声明可变时,上述操作就可行了。
fn main(){
let mut x = 0; //[! code focus]
println!("x:{}",x) // 0
x = 10;
println!("x:{}",x) // 10
}
当尝试改变一个前面指定为不可变的值时我们会得到编译期错误,这点很重要,因为这种情况很可能导致 bug。如果代码的一部分假设某个值永远不会更改,而代码的另一部分更改了该值,那很可能第一部分代码以不可意料的方式运行。这个 bug 的根源在实际开发中可能很难追踪,特别是第二部分代码只是偶尔变更了原来的值。Rust 编译器保证了当声明了一个值不会改变时,那它就真的不可改变,所以不必亲自跟踪这个值。这可以使得代码更容易理解。
常量
相较于变量而言,常量不存在 “可变”这个概念,常量一旦声明,就再也不会改变,通常适用于一些永远不会改变的值。值得注意的是,不同于变量使用let
声明,常量用const
声明,并且必须标注常量类型
。常量可以在任意作用域
内声明,包括全局作用域,这对于代码中很多部分都需要知道一个值的情况特别有用。最后一个不同点是常量只能设置为常量表达式,而不能是函数调用的结果或是只能在运行时计算得到的值。
//常量声明必须标注类型
const CONSTANT:i32 = 30 * 30;
//相较于let声明可以使用函数调用结果,const声明只能使用常量表达式
let x = plus(5);
fn plus(num:i32)->i32{
num + 1
}
const X:i32 = plus(5)
//panic!calls in constants are limited to constant functions, tuple structs and tuple variants
遮蔽(Shadow)
遮蔽是当以相同的名字再次声明变量时,第二个变量遮蔽了第一个变量,再次使用这个变量时,将获得第二个值。通过重复使用let
声明实现遮蔽变量,如下所示:
fn main() {
let x = 5;
let x = x + 1;
{
let x = x * 2;
println!("The value of x in the inner scope is: {}", x); // 12
}
println!("The value of x is: {}", x); //作用域结束,遮蔽失效,x恢复为6
}
这个程序首先将数值 5
绑定到 x
。然后通过重复使用 let x =
来遮蔽之前的 x
,并取原来的值加上 1
,所以 x
的值变成了 6
。在内部作用域内,第三个 let
语句同样遮蔽前面的 x
,取之前的值并乘上 2
,得到的 x
值为 12
。当该作用域结束时,内部遮蔽结束并且 x
恢复成 6
.遮蔽相较于 mut
声明具有更高的灵活性:
- shadow更加不容易更改变量的值。相较于
mut
声明的变量x,直接使用x=...即可完成更改,而shadow需要使用let再次声明才能更改x的值。 - shadow更加的灵活。
mut
变量直接再赋值时不允许改变变量的类型,而使用shadow
通过 let 再次声明则不限制数据类型
。
fn main(){
//shadow
let spaces = " ";
let sapces = spaces.len()
//mut
let mut spaces = " ";
spaces = spaces.len() //expected `&str`, found `usize`
}