Skip to content

变量与可变性

在Rust中,初特殊声明外,默认情况下的变量是不可变的immutable,这一特征让你充分利用 Rust 提供的安全性和简单并发性的方式来编写代码。不过你也可以选择让变量是可变的mutable。不可变变量意味着一旦声明后值就不能改变,如果尝试改变会发生什么,接下来尝试用下面的代码来分析。

rust
	fn main(){
		let x = 0;
        println!("x:{}",x)
        x = 10;
        println!("x:{}",x)
	}

通过运行上述代码,将收到编译器的报错,因为在第二行第一次声明该变量时,并未标识其为可变。具体原因为:cannot assign twice to immutable variable x(不能对不可变变量二次赋值).而声明可变时,上述操作就可行了。

rust
	fn main(){
		let mut x = 0;  //[! code focus]
        println!("x:{}",x) // 0
        x = 10;
        println!("x:{}",x) // 10
	}

当尝试改变一个前面指定为不可变的值时我们会得到编译期错误,这点很重要,因为这种情况很可能导致 bug。如果代码的一部分假设某个值永远不会更改,而代码的另一部分更改了该值,那很可能第一部分代码以不可意料的方式运行。这个 bug 的根源在实际开发中可能很难追踪,特别是第二部分代码只是偶尔变更了原来的值。Rust 编译器保证了当声明了一个值不会改变时,那它就真的不可改变,所以不必亲自跟踪这个值。这可以使得代码更容易理解。

常量

相较于变量而言,常量不存在 “可变”这个概念,常量一旦声明,就再也不会改变,通常适用于一些永远不会改变的值。值得注意的是,不同于变量使用let声明,常量用const声明,并且必须标注常量类型。常量可以在任意作用域内声明,包括全局作用域,这对于代码中很多部分都需要知道一个值的情况特别有用。最后一个不同点是常量只能设置为常量表达式,而不能是函数调用的结果或是只能在运行时计算得到的值。

rust
	//常量声明必须标注类型
	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声明实现遮蔽变量,如下所示:

rust
    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 再次声明则不限制数据类型
rust
	fn main(){
		//shadow
        let spaces = "   ";
        let sapces = spaces.len()
        //mut
        let mut spaces = "   ";
        spaces = spaces.len() //expected `&str`, found `usize`
	}