前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rust 往事 | Loop 和 While True 之争

Rust 往事 | Loop 和 While True 之争

作者头像
张汉东
发布2020-09-01 09:53:28
1.1K0
发布2020-09-01 09:53:28
举报
文章被收录于专栏:Rust 编程Rust 编程

理清头脑混沌,觉醒心智天地

我不太清楚 「Rust 往事」会不会是一个系列,先建个专栏再说。 本来想把 「往事」限定于 1.0 版本之前,但又觉得太狭隘了。Rust 是一门不断向前发展的语言,所谓往事,我觉得应该是 Rust 在发展过程中,经历过的所有决策和讨论。 一切过往,皆为序章。

引子

我曾经一直想不明白一个问题:为什么下面代码中 while true 无法通过编译 ?

代码语言:javascript
复制
fn main() {
    let mut a;
    while true {
         a = 1;
         break ;
    }
    println!("{}", a); // error[E0381]: borrow of possibly-uninitialized variable: `a`
}

而将 while true 换为 loop 则可以通过编译:

代码语言:javascript
复制
fn main() {
    let mut a;
    loop {
         a = 1;
         break ;
    }
    println!("{}", a);
}

我清楚它们之间的区别, while true 在编译期静态分析的时候和 loop 不太一样。

前者因为是 while 条件,所以编译器无法在编译期确定它的值到底是不是 true,因为 while 表达式的条件位置并非一个 常量上下文,所以无法在编译期求值,而只能检查类型。

后者则因为是永久循环,必然会执行一次,何况这里又加了 break,所以编译器会在编译期将 a 直接初始化为常量 1。即便这里不加 break,编译器也会进行初始化,大不了加个 goto 指令一直初始化。

之前 const fn 中无法使用 while 也就罢了,现在 1.46 版本中 const fn 增加了对 if/ while 的支持,可为什么还不愿意(并非识别不了)识别 while true 呢?

loop 和 while true 之争

于是,我翻了一下 Rust 语言源码仓库里的issues,找到一条有意思的 issues #12975:

「Remove `loop` keyword from the language」 ,地址:https://github.com/rust-lang/rust/issues/12975。

什么情况?从 Rust 中移除 loop 关键字 ?仔细看了一下,才发现是 2014 年的。该 Issues 建议:

  1. 移除 loop 关键字,换成 while true。注意,这里是将 while true 整体来替代 loop。因为其他很多语言都是用的 while true ,这里就不必要加 loop 了。
  2. while true 可以简化为 while { ... } .

这个建议看上去,好像是挺有道理。于是,另外一个人就马上响应,写了一份 RFC:「Propose replacing the `loop` keyword with `while true`」,地址:https://github.com/rust-lang/rfcs/pull/429。

这个 RFC 当然没有被通过审核,否则现在就看不到 loop 关键字了,官方团队以「没有兴趣删除 loop 为由,关闭了此 RFC」。看当时 RFC PR 下面的讨论,nrc 其实说了具体的理由:「这种更改,其实是在区别对待 while <condition == true > 和 while true」,这种设计比较粗鲁。假如 while 后面加了一个被识别为 true 的常量表达式,用不用通过编译?

Rust 语言设计的原则之一,就是高度一致性。这样的设计就搞的很迷。

从现在这个时间节点上回头看,Rust 官方没有接受这个 RFC 是对的。

至此,我的问题也迎刃而解

虽然在编译期识别 true 字面量易如反掌,但整体来看,while true 其实属于一种特殊的情况,更为普遍的是 while (constexpr == true) 的情况,如果后者的条件表达式越复杂越难判断到底是不是 true。

为了保持语言的一致性,就不能给 while true 开小灶。语言缺乏一致性,对于开发者来说,其实是一种灾难。

妥协

即便如此,while true 依然是个问题。

于是 Rust 团队增加了一个 lint : #[warn(while_true)] ,默认情况下是 warn,但也可以使用,#[deny(while_true)] 和 #[allow(while_true)] 。

代码语言:javascript
复制
warning: denote infinite loops with `loop { ... }`
 --> src/lib.rs:6:5
  |
6 |     while true {
  |     ^^^^^^^^^^ help: use `loop`
  |
  = note: `#[warn(while_true)]` on by default

当你习惯性使用 while true 的时候,Rust 会以警告的方式提示你:无限循环请使用 loop。但是你执意要使用 while true 的话,就最好加上 `#[allow(while_true)]` 。然而,我其实更喜欢用 loop,简单明了。

这其实也算是 Rust 语言设计上的一种妥协吧。原因有二:

  1. while true 在语义上确实会让人理解为无限循环,没毛病。
  2. 有些人确实喜欢用 while true,你不能不让他用。

像这样通过 lint 的方式来提示开发者也是一种很好的方式,美中不足的是,这个 warning 还缺乏一个解释,解释为什么 while true 和 loop 的这个区别。这也是为什么有这篇文章的原因。

小结

从这件小故事中看得出来,Rust 语言团队坚守语言设计原则,才能有现在的 Rust。这样的争论,其实在 Rust 社区发生过不少次,比如稳定异步特性的过程中,Pin的引入,以及 async/await 语法的设计等等。

希望后面有时间可以继续挖掘这些过往的故事。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 觉学社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档