Rust 往事 | Loop 和 While True 之争

原创
2020/08/31 01:53
阅读数 1.8K
 

点击上方蓝字关注我们

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


我不太清楚 「Rust 往事」会不会是一个系列,先建个专栏再说。

本来想把 「往事」限定于 1.0 版本之前,但又觉得太狭隘了。Rust 是一门不断向前发展的语言,所谓往事,我觉得应该是 Rust 在发展过程中,经历过的所有决策和讨论。

一切过往,皆为序章。


引子


我曾经一直想不明白一个问题:为什么下面代码中   while true     无法通过编译 ?
fn main() {    let mut a;    while true {         a = 1;         break ;    }    println!("{}", a); // error[E0381]: borrow of possibly-uninitialized variable: `a`}
而将 while true  换为 loop 则可以通过编译:
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)] 。
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 语法的设计等等。
希望后面有时间可以继续挖掘这些过往的故事。

本文分享自微信公众号 - 觉学社(WakerGroup)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
Rust必然走向C++的老路,有效代码将被辅助设定给淹没。
2020/09/01 12:45
回复
举报
其实在大部分没有loop的语言中,比如c,c++,java,C#,javascript等 大部分情况下都是使用while(true)来表达无限循环然后break的,当然也有一部分人是for(;;)的写法
2020/08/31 19:57
回复
举报
更多评论
打赏
2 评论
0 收藏
0
分享
返回顶部
顶部