Rust 往事 | Loop 和 While True 之争
理清头脑混沌,觉醒心智天地
我不太清楚 「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 建议:
- 移除 loop 关键字,换成 while true。注意,这里是将 while true 整体来替代 loop。因为其他很多语言都是用的 while true ,这里就不必要加 loop 了。
- 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 语言设计上的一种妥协吧。原因有二:
- while true 在语义上确实会让人理解为无限循环,没毛病。
- 有些人确实喜欢用 while true,你不能不让他用。
像这样通过 lint 的方式来提示开发者也是一种很好的方式,美中不足的是,这个 warning 还缺乏一个解释,解释为什么 while true 和 loop 的这个区别。这也是为什么有这篇文章的原因。
小结
从这件小故事中看得出来,Rust 语言团队坚守语言设计原则,才能有现在的 Rust。这样的争论,其实在 Rust 社区发生过不少次,比如稳定异步特性的过程中,Pin的引入,以及 async/await 语法的设计等等。
希望后面有时间可以继续挖掘这些过往的故事。
- 从零开始搭建前端数据监控系统(二)-前端性能监控方案调研
- 14个你可能不知道的JavaScript调试技巧
- Kafka剖析系列之高可用(下)
- 11 个简单的 Java 性能调优技巧
- NativeScript工作原理
- 如何合并Git 代码库中牛人的代码到自己的库
- Kafka剖析系列之Consumer解析
- android之View绘制
- 高性能JavaScript-JS脚本加载与执行对性能的影响
- CSS3伪类和伪元素的特性和区别
- Kafka剖析系列之Benchmark
- 初探React与D3的结合-或许是visualization的新突破?
- Redis 在Centos Linux 上的启动脚本
- 理解JavaScript的临时包装对象
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- thinkphp框架使用JWTtoken的方法详解
- Laravel创建数据库表结构的例子
- laravel按天、按小时,查询数据的实例
- 浅谈laravel中的关联查询with的问题
- 解决Laravel 不能创建 migration 的问题
- 使用tp框架和SQL语句查询数据表中的某字段包含某值
- Laravel框架中集成MongoDB和使用详解
- thinkphp5 模型实例化获得数据对象的教程
- 浅谈laravel框架sql中groupBy之后排序的问题
- php 比较获取两个数组相同和不同元素的例子(交集和差集)
- Laravel 5.5 异常处理 & 错误日志的解决
- Laravel 框架返回状态拦截代码
- PHP getID3类的使用方法学习笔记【附getID3源码下载】
- PHP读取Excel内的图片(phpspreadsheet和PHPExcel扩展库)
- 浅谈laravel 5.6 安装 windows上使用composer的安装过程