为什么 Rust 需要局部变量隐藏

2,600 阅读5分钟

什么是变量隐藏

在 Rust 的世界中,变量可以被一个同名的变量覆盖掉的现象就叫做隐藏。这意味着我们随后使用这个名称时,他指向的将会是第二个变量。我们可以重复使用let关键字并配以相同的名称来不断地隐藏变量:

fn main() {
  let x = 5;

  let x = x + 1;

  let x = x + 2;

  println!("The value of x is: {}", x);
}

按照世界上没有完全一样的两个东西的原则(上一秒的你也不等于下一秒的你),这前后两个变量并不会完全一样。我并没有看过 Rust 源码,个人理解是这两个变量指向的内存空间是不一样的。所谓隐藏不过是编译器在编译的时候去做了区分。子非编译器,安知compiler之乐乎?

隐藏机制与mut(mutable)的不同:

  1. 如果不是在使用 let 关键字的情况下重新为这个变量赋值,则会导致编译错误。通过使用let,我们可以对这个值执行一些列的变化操作,并允许这个变量在操作完成后保持自己的不可变性。
  2. 由于重复使用 let 关键字会创建出新的变量,所以我们可以在复用变量名称的同时改变它的类型。

隐藏特性通常被用在需要转换值类型的场景中,如果只是改变值本身 mut 关键字就够用。

为什么Rust需要变量隐藏?

这是 reddit rust 话题下的一个问题,我这里翻译一下。

问题

我最近发现 Rust 不像其他类C语言,它允许在一个块作用域中定义多个拥有相同名称的变量:

let name = 10i;
let name = 3.14f64;
let name = "string";
let name = name; // "string" again, this definition shadows all the others

至少从我的 C++ 背景来说,第一次看到这个特性着实有点吓人。

这个特性来自哪里?它提供了什么好处?

回答

变量隐藏与仿射类型(affine types)具有很多协同作用。例如:

let foo = foo.unwrap();

你在其中重新绑定 foo 的同时引用 unwrap() 的结果,因此旧 foo 由于该原因而变得不可访问。——变量指向了新的内存空间。


好处是使用一个单词来表示共同的变量,例如 c 用于绘制上下文。变量可以被改变类型,Rust-Graphics 大量地依赖该特性。每一个方法返回一个新的类型,并且当上下文提供足够的信息去绘制时,你只能调用.draw(gl)


我经常使用的单个字母是:

  • ab 用作二进制操作的参数
  • cdg 用作图形绘制
  • ijk 用作索引
  • nm 用作长度
  • xyzt 作为空间坐标系

有时我也使用pq或者vu 作复杂的数学运算。


我认为变量隐藏的最佳论据是阻止对象可变性的能力。

let mut vec = Vec::new();
vec.push(1i);
vec.push(2i);
let vec = vec;

但是,对于中间变量,我也很喜欢。有时,通过let绑定将长方法链分成两行只是更漂亮。您只需两次使用变量名来代替使用 let temp,这样,临时变量不会使函数名称空间的其余部分杂乱无章。


我不确定,但我认为此功能可将可变性降至最低。您可以使用新值重新声明它,而不用突变一个变量。

无论如何,它并没有看起来那么糟糕。类型系统禁止使用int代替浮点数或字符串。

确实,此功能可能会导致错误,但也可以防止它们。没有隐藏,您常常必须为变量(相同类型)使用不同的名称,这使得使用错误的变量成为可能。


我昨天也注意到了这一点。我宁愿没有它,因为它引入了难以发现的错误。

我自己的C ++代码中有与隐藏相关的错误(就在上周)。此外,由于隐藏局部变量,Gecko中也存在bug,因此显然这很危险。

我知道Rust是一种旨在防止错误的语言(即使它降低了便利性),所以我想知道为什么允许这样做。值得冒着出BUG的风险吗?

也有人评论说lint有一个选项可以警告可变阴影。会有这样的选择吗?但愿如此。

顺便提一句。该线程还有一些用例,人们如何使用隐藏,因此对此线程感兴趣的人应该通读它。


我经常使用隐藏来防止再次引用另一个变量。这是我从OCaml那里习得的一种习惯,在该习惯下,隐藏是允许的并且是惯用的。

比如,在 trans 中我经常隐藏来终止块变量,因为再次使用它们是一个错误。这样,隐藏可以成为防止错误的强大工具。

总结

这个问答中,整体的意见比较一致,就是隐藏特性乍看起来很不爽,但是用多了就会惊讶于它的安全性、便捷性。凡事有捧就有踩,还是有老哥说出来隐藏用多了,很难调试,由于老哥过于啰嗦,懒得翻译原文如下:

个人觉得这有点杠了,所有设计一旦被滥用就会变得不对劲。总体来说隐藏带来的好处是大于益处的。

故事未尽

寻了一圈,未得一个 Rust 交流群,自己组了一个,欢迎大佬加入:

涂鸦智能大量优质 HC,欢迎大家加入,需要内推加我微信 yang_jun_ning,或直接发简历到邮箱 youngjuning@aliyun.com