编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

Rust的不足之处,让它无法成为一门成熟的编程语言

gowuye 2024-04-25 04:45 8 浏览 0 评论

虽然我并不反对 Rust 本身,并且一直在用 Rust 开发自己的项目,但我还是发现它有一些不足之处,让它无法成为一门成熟的编程语言。在这篇文章里,我想把这些问题列出来,并解释为什么我会这样认为,即使它们对我没有任何影响。

Rust 语言本身的问题

首先,Rust 没有正式的语言规范。我的意思是,尽管对语法和对象等方面进行了解释,但没有正式的规则来描述语言特性可以是什么或不可以是什么。在 ISO C 语言标准里,几乎每一项都有三到四个描述片段:正式的语法约束 (即哪些东西是不被允许的或者不能用它完成哪些事情)、语义 (即它可以做什么、它是如何影响程序的、有哪些需要注意的地方),而且可能还会列出一些例子。Rust 参考( https://doc.rust-lang.org/reference/ )中是这样描述结构体的:语法 (没有异议)、类似“结构体是用关键字 struct 定义的名义结构体类型”这样的定义、示例、在示例中间简短地提到空结构体,最后以“结构体没有指定精确的内存占用”结尾。我知道添加新特性比写文档更重要,但这样做确实很蹩脚。

一门成熟的编程语言 (版本到了 1.0) 应该有正式的规范,对于开发编译器的人和使用这门语言的程序员来说都应该有用。例如,对于结构体的定义,我发现至少缺少了这些东西:提到你可以 impl(实现)、将元组拆分成独立的项、说明为什么有匿名的元组而不是匿名的结构体,当然,还要使用适当的布局,让示例中重要的信息 (例如关于内存占用) 不至于丢失。

现在说说我经常遇到的问题,我不知道是我理解错了还是编译器理解错了。而且,由于没有正式的规范,我不知道是哪个出了问题 (即使更有可能是我理解错了)。

调用函数 / 方法。看看这个简单的示例:

struct Foo { a: i32 }
impl Foo { fn bar(&mut self, val: i32) { self.a = val + 42; } }
fn main() { 
  let mut foo = Foo { a: 0 }; 
  foo.bar(foo.a);
}

因为使用了借用,这个无法正常编译,但问题是编译器不是应该“聪明”地在调用之前创建一个 foo.a 的副本吗?我不确定,但 IIRC 的当前实现首先可变地借用对象,然后尝试借用参数。真的是这样吗?如果是,为什么是这样?有人告诉我,新版本编译器处理得很好,但问题仍然存在 (这是编译器的问题还是调用定义发生变化了?)

另一个是关于函数参数求值的警告。这里有一个简单的例子:

let mut iter = “abc”.chars();
foo(iter.next().unwrap(), iter.next().unwrap(), iter.next().unwrap());

所以,是调用 foo(‘a’,‘b’,‘c’) 还是 foo(‘c’,‘b’,‘a’)?在 C 语言中,它是 undefined,因为它取决于参数在当前平台上是如何传递的。在 Rust 中,它是 undefined,因为没有正式的规范告诉你它应该是怎样的。如果你要通过索引访问调用者对象,比如 handler[iter.next().unwrap() as usize].process(iter.next().unwrap()),情况会更糟糕。

另一个让我抓狂的是 trait。对于我来说,理解所有权、生命周期、借用这些概念都没什么问题,但 trait 几乎每次都会让我抓狂。我隐隐约约地知道这是“因为 trait 被实现成调用表”,但问题是它们应该被这样实现吗?它们的约束是什么?当你有一个超级 trait(例如,trait Foo: Bar),你就不可能在不编写大量样板代码的情况下轻易地将它转换成子 trait(例如 &Foo -> &Bar)。更糟糕的是,如果你将一个对象转成 Box,就没有办法找回原来的对象。重申一下:问题不在于我笨,而在于 Rust 缺乏描述,比如如何实现才是对的、为什么我想要的东西会如此之难。然后,我意识到我需要修改自己的代码来绕过这些限制。

rustc 的问题

其实我不是想讨论编译速度问题,尽管有点扰人,但它本身并不是个问题。我想指出的是一些一门成熟的编程语言不应该有的问题,而一门语言只有一个编译器就是其中的一个问题。

首先,自举过程非常糟糕。我知道这并不容易,但如果 Rust 被认为是一门系统编程语言,那么就应该能够通过几个步骤来自举编译器。例如,IIRC Guix 对 C 编译器的自举过程:用简单 C 编译器 (通常可以通过手动编写汇编代码实现) 编译 TCC,用 TCC 编译 GCC 2.95,用 GCC 2.95 编译 GCC 3.7,用 GCC 3.7 编译 GCC 4.9。对于 rustc 来说,你要么使用原始的编译器(使用 OCaml 开发的),然后使用前一个版本编译后一个版本 (即使用 1.16 编译 1.17),要么使用 mrustc(使用 C++ 开发的),它可以编译 1.19 或 1.29(没有借用检查),然后使用 1.29 编译 1.30,使用 1.30 编译 1.31,以此类推。这里的问题是,你不能跳过版本,比如用 rustc 1.36 编译 rustc 1.46。在我看来,你应该有一种编译器,效率可以不高,但要用一种老编译器能够理解的方言来开发,即使用 rustc 1.0 编译 1.10 的编译器,这个编译器可以用来编译 1.20,以此类推。当然,这是个理论问题,所以可能会浪费资源,但对编译器设计本身是有好处的。

接下来是 LLVM 依赖问题。我知道 LLVM 有很多优点 (比如不需要担心在多平台上的代码生成和优化问题),但它也有一些缺点。首先,没有一个真正的自托管编译器 (这也是一个理论问题,但仍然值得我们思考)。其次,它的一些行为会限制我们。例如,我看到有很多人抱怨调试构建的速度太慢,主要是因为 LLVM 后端导致的。我猜想它仍然不能做一些与内存相关的优化,因为它的设计参考了 C++ 编译器,而后者仍然存在奇怪的多内存访问问题。我知道现在有 cranelift,所以希望这个问题可以得到改善。

最后,还有一个与上一个问题相关的问题。Rust 对汇编的支撑很差。当然,并不是所有人都需要汇编支持,但面向系统编程的语言除了支持高级语言代码外还应该要支持编译汇编,所以也应该支持汇编文件,即使不像 GAS 那样提供了丰富的预处理器语法。我们可以用 build.rs 来调用外部汇编器,但这样一点也不好。

其他问题

Rust std 库有一个问题,它对于操作系统的交互来说并没有什么用。如果我想对任意一个 UNIX 系统做一些事情,至少需要导入 libc,并链接到外部 libc(它是运行时的一部分)。一种解决方案是把 musl 翻译成 Rust,这样至少可以省掉链接步骤。但更好的解决方案应该是支持使用 std 里的 syscall(),因为很多有趣的 libc 函数只是对 syscall() 进行了包装 (例如 open()/write()/ioctl())。

我不是 Rust 的架构师,也不可能成为 Rust 的架构师。但是我知道,Rust 要成为一门成熟的适合系统开发的编程语言,缺少了一些东西 (本质上就是:完全自托管、规范和能够不借助 C 编译器和汇编实现与底层的交互)。希望这些问题能够得到解决。

原文链接:

https://codecs.multimedia.cx/2020/09/why-rust-is-not-a-mature-programming-language/

延伸阅读:

我为什么反对使用Rust?-InfoQ

自从尝了Rust,Java突然不香了-InfoQ

关注我并转发此篇文章,私信我“领取资料”,即可免费获得InfoQ价值4999元迷你书,点击文末「了解更多」,即可移步InfoQ官网,获取最新资讯~

相关推荐

R语言数据挖掘实践——支持向量机的常用函数
R语言数据挖掘实践——支持向量机的常用函数

e1071包是R语言中用于支持向量机建模与分析的软件包,其主要用于支持向量机的模型构建,提供核心函数svm()来建立支持向量机的基础模型,并且可辅助使用pred...

2024-05-18 12:15 gowuye

R数据分析:如何做聚类分析,实操解析
R数据分析:如何做聚类分析,实操解析

Clusteringisabroadsetoftechniquesforfindingsubgroupsofobservationswi...

2024-05-18 12:14 gowuye

用R语言做数据分析——马赛克图
用R语言做数据分析——马赛克图

到目前为止,我们已经学习了许多可视化定量或连续型变量间关系的方法。但如果变量是类别型的呢?若只观察单个类别型变量,可以使用柱状图或者饼图;若存在两个类别型变量,...

2024-05-18 12:14 gowuye

用R语言做数据分析——方差分析基本概论
用R语言做数据分析——方差分析基本概论

在实际工作中,影响一件事的因素是很多的,我们总是希望通过各种试验来观察各种因素对试验结果的影响。例如,不同的生产厂家、不同的原材料、不同的操作规程,以及不同的技...

2024-05-18 12:14 gowuye

R语言数据分析实战:数据清洗与可视化
R语言数据分析实战:数据清洗与可视化

《R语言数据分析实战:数据清洗与可视化》是一本深入浅出的实践指南,专为对数据分析感兴趣的读者精心编撰。本书旨在帮助读者掌握R语言这一强大的统计分析工具,通过实例...

2024-05-18 12:13 gowuye

用R语言做数据分析——双因素方差分析
用R语言做数据分析——双因素方差分析

在双因素方差分析中,受试者被分配到两因子的交叉类别组中。以基础安装中的Tooth-Growth数据集为例,随机分配60只豚鼠,分别采用两种喂食方法(橙汁或维生素...

2024-05-18 12:13 gowuye

用R语言做数据分析——独立两样本和K样本检验
用R语言做数据分析——独立两样本和K样本检验

coin包简介对于独立性问题,coin包提供了一个进行置换检验的一般性框架,通过这个包,我们可以回答如下问题:响应值与组的分配独立吗?两个数值变量独立吗?两个类...

2024-05-18 12:13 gowuye

用R语言做数据分析——用回归做方差分析
用R语言做数据分析——用回归做方差分析

之前提到方差分析和回归都是广义线性模型的特例,之前文章的所有设计都可以用lm()函数来分析。为了更好地理解输出结果,需要弄明白在拟合模型时,R语言是如何处理类别...

2024-05-18 12:13 gowuye

数据分析R语言——数据结构
数据分析R语言——数据结构

数据分析R语言——数据结构数组数组(array)与矩阵类似,但是维度可以大于2.数组通过array()函数创建。形式如;myarray<-array(v...

2024-05-18 12:13 gowuye

R语言数据挖掘实践——关联分析的常用函数
R语言数据挖掘实践——关联分析的常用函数

arules和arulesViz是R语言中两个专用于关联分析的软件包。其中arules用于关联规则的数字化生成,提供Apriori和Eclat这两种快速挖掘频繁...

2024-05-18 12:12 gowuye

R语言数据挖掘实践——判别分析的常用函数
R语言数据挖掘实践——判别分析的常用函数

判别算法在R语言中实现主要涉及4个软件包中的相关函数,它们依次为MASS、klaR、class和kknn。其中MASS包含有大量实用而先进的统计计数函数及适用数...

2024-05-18 12:12 gowuye

用R语言读取Excel、PDF和JSON文件,终于有人讲明白了
用R语言读取Excel、PDF和JSON文件,终于有人讲明白了

导读:本文将讨论Excel、PDF等文件的读取,以及相应函数的参数设置。作者:刘健邬书豪如需转载请联系华章科技下图总结了主要程序包,希望读者在日常练习和工作中...

2024-05-18 12:12 gowuye

R语言数据挖掘实践——聚类分析的常用函数
R语言数据挖掘实践——聚类分析的常用函数

使用R语言可以轻松实现聚类分析,stats、cluster、fpc和mclust是常用的四个聚类分析软件包。stats主要包含一些基本的统计函数,如用于统计计算...

2024-05-18 12:12 gowuye

用R语言做数据分析——时间序列分类
用R语言做数据分析——时间序列分类

时间序列分类是根据已标注的时间序列建立一个分类模型,然后使用分类模型预测未标记时间序列的类别。从时间序列中抽取出新特征肯呢个有助于提高分类模型的性能。特征提取技...

2024-05-18 12:11 gowuye

一文看懂用R语言读取Excel、PDF和JSON文件(附代码)
一文看懂用R语言读取Excel、PDF和JSON文件(附代码)

导读:本文将讨论Excel、PDF等文件的读取,以及相应函数的参数设置。作者:刘健邬书豪如需转载请联系华章科技下图总结了主要程序包,希望读者在日常练习和工作中...

2024-05-18 12:11 gowuye

取消回复欢迎 发表评论: