06_变量与可变性

变量与可变性

Rust中的变量特性

Rust中变量的定义格式:

let 变量名: 数据类型 = 对应的值;		//不可变的变量
let mut 变量名: 数据类型 = 对应的值;	//可变的变量

在Rust中,变量的声明默认是不可变的。这是 Rust 提供给你的众多优势之一,让你得以充分利用 Rust 提供的安全性和简单并发性来编写代码。

不过也可以使用一些方法把变量的不变性打破,让变量是可变的。要结合实际场景使用变量的不变与可变。

当变量不可变时,一旦值被绑定一个名称上,你就不能改变这个值。

例如:

fn main() {
    let x = 3; // 当前x是一个不可变的变量,已经绑定它的值为3
    x = 5;	//试图改变x的值,则在编译阶段就会报错。
}

在命令行使用cargo check时就会报以下的错:

error[E0384]: cannot assign twice to immutable variable `x`

即不可以再次赋值给不可变的变量x.

因为使用let声明的变量默认是不可变的,所以x一开始赋值是3,所以直到x的生命周期结束了都不可以修改x的值。

如果想修改变量的值,那就需要声明变量是可变的,对应的操作也很简单,只需要在let和变量名之间插入mut关键字即可。

mut是mutable的缩写

例如:

fn main() {
    let mut x = 3; // 当前x是一个可变的变量,已经绑定它的值为3
    x = 5;	//试图改变x的值,没有任何问题,因为已经声明x是可变的变量。
}

Rust中对变量的定义可以采用以下方式:

//let 变量名 = 值+类型;
let i = 3i32;	//等效let i: i32 = 3;

Rust中的常量

在Rust中,很奇怪的现象就是,变量默认是不可变的,而常量也是不可以改变的,但是这两个是不一样的东西。

在Rust中变量默认不可变,但是可以通过加一个mut关键字就可以修改变量的值。在Rust中,对变量还有“隐藏”的操作,后面会讲到。

但是常量一旦定义了就不可以改变。

简单理解:(在Rust中)

常量:不可变的

变量:默认是不可变的变量

常量一些规范:

  • 常量一般使用全大写加下划线组合命名
  • 不可以使用变量来赋值给常量
  • 一旦定义就不可改变

例子:

const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

常量的名称是 THREE_HOURS_IN_SECONDS,它被赋值为60 * 60 * 3的结果 。编译器能够在编译时计算一组有限的操作,这使我们可以选择以更容易理解和验证的方式写出此值,而不是将此常量设置为值10,800。有关声明常量时可以使用哪些操作的详细信息,请参阅 Rust Reference 的常量求值部分

在声明它的作用域之中,常量在整个程序生命周期中都有效,此属性使得常量可以作为多处代码使用的全局范围的值,例如一个游戏中所有玩家可以获取的最高分或者光速。

将遍布于应用程序中的硬编码值声明为常量,能帮助后来的代码维护人员了解值的意图。如果将来需要修改硬编码值,也只需修改汇聚于一处的硬编码值。

Rust中的隐藏

我们可以定义一个与之前变量同名的新变量,Rustacean 们称之为第一个变量被第二个 隐藏(Shadowing),这意味着当您使用变量的名称时,编译器将看到第二个变量。实际上,第二个变量“遮蔽”了第一个变量,此时任何使用该变量名的行为中都会视为是在使用第二个变量,直到第二个变量自己也被隐藏或第二个变量的作用域结束。可以用相同变量名称来隐藏一个变量,以及重复使用 let 关键字来多次隐藏,如下所示

fn main() {
    let x = 5;		// x1

    let x = x + 1;	// x2 = x1 + 1;
	// x1已经被遮蔽,往后看到的x默认是x2
    {	// 引入一个新的域
        let x = x * 2;	// x3 = x2 * 2;
        // x2被遮蔽,往后看到的x默认是x3
        println!("The value of x in the inner scope is: {x}");	//打印x3的值
    } // 出域,x3的生命周期结束,x2被回显,往后看到的x默认是x2

    println!("The value of x is: {x}");	// 打印x2的值
}	// 出域,x2的生命周期结束,x1被回显,但x1的生命周期也结束,所以x1和x2都死亡,被栈回收内存

程序一开始,使用一个x变量绑定到5身上,即使用5赋值给x变量(不可变),将x+1的值赋值给名字和x相同的变量(不可变)中,于是原来的x就被遮蔽,在后续的代码中如果使用到了x则是使用第二个x变量,直到该x被遮蔽或者生命周期结束。

隐藏和mut的区别

隐藏与将变量标记为 mut 是有区别的。

  • 当不小心尝试对变量重新赋值时,如果没有使用 let 关键字,就会导致编译时错误。

  • 通过使用 let,我们可以用这个值进行一些计算,不过计算完之后变量仍然是不可变的。

  • 当再次使用 let 时,实际上创建了一个新变量,我们可以改变值的类型,并且复用这个名字。

例如:

fn main() {
    let a = 5;
    // a = 9;	编译错误,a是不可变的变量,不可重新赋值
    test(a);
    println!("main: a = {}", a);
}

fn test(a: i32) {
    {
        let a = a + 2;	// 可以再次let隐藏变量,即第二个a遮蔽了第一个a
        println!("test 1: a = {}", a);	//7
    }	//第二个a死亡
    {
        let mut a = a + 2;	//因为第二个a死亡了,所以第一个a回显,回显后再次被第三个a遮蔽,并且第三个a是可变的
        let b = a + 10;
        a = 8;
        println!("test 2: a = {}\tb = {}", a, b);
    }	//第三个a死亡
    {
        let a: String = String::from("Hello"); //第四个a遮蔽第一个a并改变了类型
        println!("test 3: a = {}", a);
    }	//第四个a死亡
    println!("test: a = {}", a);	//第一个a回显
}

结果:

test 1: a = 7
test 2: a = 8   b = 17
test 3: a = Hello
test: a = 5
main: a = 5

因为mut是声明变量是可变的,但是它的可变只是值变了,但类型并不能改变,而let隐藏这是使用一个新的变量来遮蔽原来的变量,新的变量当然可以是新的值也可以是新的类型。

let mut spaces = "   ";
spaces = spaces.len();

编译器报错:

error[E0308]: mismatched types
  |
2 |     let mut spaces = "   ";
  |                      ----- expected due to this value
3 |     spaces = spaces.len();
  |              ^^^^^^^^^^^^ expected `&str`, found `usize`

现在我们已经了解了变量如何工作,让我们看看变量可以拥有的更多数据类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值