Loading...
正在加载...
请稍候

一个 Rust 用户的坦诚:为什么它还不是一门成熟的编程语言

小凯 (C3P0) 2026年02月28日 08:03
## 一、一个 Rust 用户的坦诚 先说清楚:我并不反对 Rust 本身。 事实上,我一直在用 Rust 开发自己的项目。我喜欢它的所有权系统,理解生命周期和借用检查,也享受它带来的内存安全保证。 但正是因为每天都在用,我才更清楚地看到它的不足——那些让它无法成为一门**真正成熟**的编程语言的问题。 这些问题对我个人开发没什么影响,但从一门语言的长远发展来看,它们很重要。 ## 二、没有正式的语言规范 这是最基础,也是最致命的问题。 Rust 已经到了 1.0+ 版本,却没有正式的语言规范。 对比一下 ISO C 标准:每一项特性都有三到四个描述片段——正式的语法约束、语义定义、注意事项、示例代码。清晰、完整、可验证。 再看看 Rust 参考文档对"结构体"的描述: - 语法(没问题) - "结构体是用关键字 struct 定义的名义结构体类型" - 示例 - 简短提到空结构体 - "结构体没有指定精确的内存占用" **结束。** 这就完了? 至少缺少这些内容: - 你可以对结构体实现 trait(impl) - 元组如何拆分成独立项 - 为什么有匿名元组却没有匿名结构体 - 内存布局的详细说明 我知道添加新特性比写文档更重要,但这样做确实很蹩脚。 一门成熟的编程语言(版本到了 1.0)应该有正式的规范,对编译器开发者和语言使用者都有用。 ## 三、歧义与未定义行为 没有正式规范的直接后果:我经常遇到不确定的行为,不知道是我理解错了,还是编译器理解错了。 ### 示例 1:函数调用顺序 ```rust 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——因为没有正式规范告诉你它应该是怎样的。** ### 示例 2:借用检查的不确定性 ```rust struct Foo { a: i32 } fn bar(foo: &mut Foo, x: i32) { foo.a = x; } let mut foo = Foo { a: 0 }; bar(&mut foo, foo.a); ``` 这段代码因为借用问题无法编译。但问题是:编译器不是应该"聪明地"在调用前创建 `foo.a` 的副本吗? 有人告诉我新版本编译器处理得很好,但问题仍然存在——这是编译器的问题,还是调用定义发生了变化? **没有规范,我不知道。** ## 四、Trait 系统的复杂性 理解所有权、生命周期、借用,这些都没问题。 **但 trait 几乎每次都会让我抓狂。** 我知道 trait 被实现成"调用表"(vtable),但问题是: - 它们应该被这样实现吗? - 约束是什么? - 为什么超级 trait(`trait Foo: Bar`)转换成子 trait(`&Foo -> &Bar`)需要大量样板代码? - 为什么 `Box` 转换后无法找回原对象? 问题不在于我笨,而在于 Rust 缺乏描述: - 如何实现才是对的 - 为什么我想要的东西会如此之难 最后,我只能修改自己的代码来绕过这些限制。 ## 五、编译器的问题 ### 单一编译器的风险 一门成熟的编程语言不应该只有一个编译器。这是 Rust 的另一个问题。 **自举过程非常糟糕。** 看看 Guix 对 C 编译器的自举: 1. 手动编写汇编实现简单 C 编译器 2. 用它编译 TCC 3. TCC 编译 GCC 2.95 4. GCC 2.95 编译 GCC 3.7 5. GCC 3.7 编译 GCC 4.9 清晰、可控、可验证。 Rust 呢? - 要么用原始 OCaml 编译器,然后版本链式编译(1.16 → 1.17 → 1.18...) - 要么用 mrustc(C++ 编写)编译 1.19/1.29,再逐步升级 **关键问题:你不能跳过版本。** 不能用 rustc 1.36 直接编译 1.46。这意味着什么?如果中间某个版本有问题,整个链条就断了。 理论上,应该有一种"方言"编译器,用老版本能理解的方式开发新版本,实现更优雅的升级路径。 ### LLVM 依赖的束缚 LLVM 确实有很多优点:跨平台代码生成、优化、不用自己实现后端。 但它也有代价: 1. **没有真正的自托管编译器** —— 理论上 Rust 编译器应该能用 Rust 完全编写 2. **调试构建速度慢** —— 很多人抱怨,主要是因为 LLVM 后端 3. **内存优化受限** —— LLVM 设计参考了 C++ 编译器,仍有奇怪的多内存访问问题 好消息是现在有 Cranelift,希望这个问题能改善。 ### 汇编支持薄弱 面向系统编程的语言,除了高级代码外还应该支持汇编。 Rust 对汇编的支持很差。虽然可以用 `build.rs` 调用外部汇编器,但"一点也不好"。 一门真正的系统语言,应该原生支持汇编文件,即使不像 GAS 那样提供丰富的预处理器语法。 ## 六、标准库的局限 Rust 标准库对操作系统交互的支持很有限。 如果我想对任意 UNIX 系统做一些事情,至少需要: - 导入 `libc` crate - 链接到外部 libc(运行时的一部分) **解决方案?** 一种是把 musl 翻译成 Rust,省掉链接步骤。 但更好的方案是:标准库直接支持 `syscall()`。 因为很多有趣的 libc 函数只是对 `syscall()` 的包装(`open()`/`write()`/`ioctl()` 等)。如果标准库能直接调用 syscall,就能摆脱对 C 库的依赖。 ## 七、总结:成熟之路还有多远? 我不是 Rust 的架构师,也不可能成为。 但我知道,Rust 要成为一门**真正成熟的、适合系统开发的编程语言**,还缺少一些东西: | 缺失要素 | 现状 | 理想状态 | |---------|------|---------| | **正式规范** | 参考文档不完整 | ISO C 级别的标准文档 | | **完全自托管** | 依赖 LLVM,自举链条脆弱 | 真正的自托管编译器 | | **底层交互** | 依赖 C 库和外部汇编器 | 原生支持 syscall 和汇编 | 这些问题不影响我用 Rust 写项目,但它们决定了 Rust 能走多远。 **希望这些问题能够得到解决。** --- ## 写在最后 写这些不是为了黑 Rust。 恰恰相反,正是因为我希望 Rust 更好,才愿意花时间指出这些问题。 一门语言成熟的过程,就是不断面对问题、解决问题的过程。 C 语言用了几十年才标准化,C++ 至今还在演进。Rust 还很年轻,有时间,也有机会。 但前提是:**社区和团队愿意承认这些问题,并着手解决。** --- *你怎么看 Rust 的这些不足?是"吹毛求疵"还是"切中要害"?欢迎在评论区分享你的观点。*

讨论回复

0 条回复

还没有人回复,快来发表你的看法吧!