绑定Rust变量会踩什么坑

讲动人的故事,写懂人的代码

3.2 变量绑定的声明和初始化分开

在3.1.1中提到,变量的声明和初始化可以分开。而这也为程序员挖了一个坑,如代码清单3-4所示。

本书代码下载链接为github.com/wubin28/book_LRBACP。本书所有的代码清单,会注明在这个链接中的文件夹位置,以便读者找到相应的没有行号的代码来运行。

下载代码之前,请先安装git。具体的安装步骤,可以询问你最喜欢用的生成式AI聊天工具。

之后,可以运行git clone命令,然后进入文件夹book_LRBACP即能看到所有代码。

代码清单3-4 在初始化完成之前误用变量

// 源代码位置:ch03/uninitialized_peril
 1 fn main() {
 3     let x: i32;
 4     if true {
 5         x = 5;
 6     }
 7     // 取消注释下面一行以查看编译错误: 变量`x`在某些执行路径上未初始化
 8     // println!("x的值是: {}", x);
18 }

代码清单3-4所对应的完整源代码,展示了"在初始化完成之前误用变量"的问题,以及如何正确初始化变量。代码分为两部分:一个有潜在问题的部分和一个修复后的部分,都涉及变量的声明和初始化。

第3行声明了一个i32类型的变量x,但没有立即初始化它。

第4-6行:在一个if表达式中初始化x。虽然这里条件始终为truex总会被赋值为5,但编译器却不放过这一点。

第8行被注释掉了。如果取消注释,就会踩坑里。这将导致编译错误,因为编译器认为x在某些执行路径上未初始化。

❗️变量初始化避坑指南
当变量的声明与初始化分开,并使用if表达式进行初始化时,如果无法确保在所有可能的执行路径上都初始化变量,那么编译会报错。

如何修复这个问题?只要在第6行后面加个else表达式,并在表达式里给x再初始化一下,让编译器确信所有执行路径都初始化即可。

在这里插入图片描述

3.3 多次绑定同一名称进行变量遮蔽

Rust中的变量遮蔽(variable shadowing),指在同一作用域内使用相同名称声明新变量的能力。新变量会"遮蔽"之前声明的同名变量,之前的变量不再有效。这允许程序员重用变量名。如下所示。

fn main() {
    let x = 5;
    let x = x + 1; // 新的x遮蔽了之前的x
    println!("x is {}", x);
}
// 输出:
// x is 6

这个特性在保持变量名简洁的同时,允许程序员在同一作用域的不同阶段,针对同一名称声明不同类型、值或可变性的新变量。需要注意的是,遮蔽和可变性(mutability)是不同的概念。

❗️变量遮蔽避坑指南

遮蔽创建了一个新变量,而非修改旧变量。这个新变量虽与旧变量同名,但可能拥有完全不同的类型、值或可变性。

变量遮蔽虽然有重用变量名的便利,但若使用不当,会让程序员踩什么坑?主要会踩3个坑。

第1个坑是忘记遮蔽更改了变量类型。变量遮蔽能创建不同类型的新变量,但粗心的程序员有时会忘记这一点,继续使用遮蔽前的类型而踩坑(踩坑源代码参见:ch03/shadow_type_amnesia)。

第2个坑是多次更改变量含义的遮蔽,引发困惑。变量遮蔽的本质,是相同的名称来声明新的变量。新的变量的含义在每次声明时,难免会发生变化。当变量的含义变化得过大时,变量名就变成错误的“指路牌”,往往让程序员产生误解而踩坑(踩坑源代码参见:ch03/shadowing_maze)。

第3个坑是忘记遮蔽更改了变量可变性。这和第1个坑有点像。在用变量遮蔽绑定新的同名变量时,可以更改变量的可变性。粗心的程序员会忘记这一点而踩坑(踩坑源代码参见:ch03/shadowed_mutability_trap)。

如果喜欢这篇文章,别忘了给文章点个“在看”,好鼓励小吾继续写哦~????

上一篇:【GreenHills】GHS的Run-Time检查功能


下一篇:electron出现乱码和使用cmd出现乱码