编程语言 Rust 的几个核心问题
我曾自称讨厌Rust,但其实只是为了抵消那种显而易见的狂热崇拜——比如Rust在Stack Overflow调查中稳居最受欢迎语言榜首。讨厌C++的理由不胜枚举,我也同样厌恶它。许多人期待更优秀的编程语言,结果却迎来了Rust。
Rust存在几个核心问题:
- 编译速度慢。我是说非常慢。比C++还慢。我知道这些年来Rust的速度提升了数倍,但客观而言我们需要它提升两个数量级,而非仅仅两倍。
- 复杂度过高。其复杂程度堪比C++。但C++有历史积淀,Rust却没有。每一步都要在
Arc<Mutex<Box<T>>>的丛林中艰难前行,这种强加的复杂性直接影响实现逻辑的质量——只见树木不见森林。C++同样存在此问题,那么最终切换语言的意义何在? - 内存安全并非至高无上。事实上,对许多应用而言,异常运行比崩溃更可取——尤其在Rust力图进驻的嵌入式领域。Rust无法实现99.999%的可靠性——它频繁崩溃。
- 处理大量可变共享状态(GUI、数据库、有状态服务、操作系统/硬件)时,Rust原生内存模型的性能表现欠佳,而非原生的unsafe操作只会带来缓慢编译、高复杂度,最终仍无法保证内存安全——这使得Rust在处理重度可变状态任务时几乎毫无意义。
C++ 确实糟糕透顶
这毫无疑问。未定义行为(UB)是该语言的本质特征,你并非偶尔遭遇UB——整个语言体系都建立在UB之上。只要进行数组索引操作,你就会立即遭遇UB,因为该语言根本不检查越界访问。我要强调的是,许多UB甚至无法用性能问题来辩解——这是C语言粗糙设计的延续,在C++中被放大到极致。关于C++的糟糕之处,我能列举一整天:
- 隐式类型转换、隐式复制、隐式构造函数、隐式对象切片,以及几乎所有隐式机制;
- 函数重载(隐式),尤其考虑到它在STL中的无处不在;
- 异常处理作为事后补丁导致的错误处理不统一;
- 在C语言诞生40年后仍需#include文本文件,且编译器对单一定义规则几乎不作检查;
- 模式组合不合理(祝你好运在派生类中重写泛型函数);
- SFINAE作为泛型编程核心机制带来的麻烦;
- T, T&, T*, std::optional, std::unique_ptr 描述相似概念,各自存在缺陷。再加个const作为点睛之笔。
因此C++复杂、不安全且编译器缓慢。Rust如何(未能)解决这些问题?
1. 编译缓慢
这并非暂时性问题——而是设计使然。一位设计者曾阐述Rust开发团队为何每次都牺牲编译速度:
https://pingcap.medium.com/the-rust-compilation-model-calamity-1a8ce781cf6c
Rust常见问题解答指出,团队已通过改进前端、中间表示语言(MIR)等多种方式进行优化。但MIR项目自2015年启动至今,仍未能显著提升编译速度(尽管加速了编译器检查)。
遗憾的是,Rust 编译速度难以显著提升。这类问题本质上存在于所有泛型密集型语言中,例如 Haskell。可以说 Rust 与 Haskell 的亲缘性远高于 C++,也可将其视为模板密集型 C++ 的变体——而模板密集型 C++ 代码同样存在编译缓慢的困境。
当你执行for i in 0..limit {}时——你不仅在迭代,更在创建范围、生成迭代器并进行迭代——所有操作都需针对具体类型进行单态化处理并单独优化(未经优化的Rust代码极其缓慢,甚至调试时都难以使用)。
在此基础上叠加强制性的借用检查机制——你就得到了极其缓慢的编译器。而你必然会频繁重编译,因为借用检查机制从不妥协。
2. 复杂性
你根本无法规避。你不可能抱着“我写的是冷路径的高级代码,不需要性能,不需要深入研究生命周期管理,只想编写高级逻辑”的态度行事。每次书写Rust代码时,你都将被迫面对底层细节。Rust没有垃圾回收机制且永远不会有——你必须半手动地将所有数据打包进所有权树中。仅写几行代码就需要精通所有权、借用和特质。
正如我之前提到的,这使得用Rust编写高级逻辑变得极其困难。正因如此,许多早期Rust采用者在处理对性能要求不高的服务时,实际上会回退到Node.js和Go——高复杂度加上缓慢的编译速度,使得仅用Rust编写复杂程序变得不切实际。
3. 内存安全
Rust 核心理念中有两项不可妥协的原则:性能与内存安全。我必须指出,Rust 设计者在内存安全方面做得过头了。众所周知容器实际上是用unsafe函数实现的,因为图灵机模型下不可能存在绝对正确的程序——必须通过精心组合不安全的构建块来构建安全程序。Node.js和Go被视为实用安全语言。Rust为内存安全牺牲了理性和实用性,最终却两者皆失——它依然无法实现100%内存安全。
谈及实用性——许多场景根本不需要绝对的内存安全。存在既能实现非安全程序,又不会执行远程代码或泄露机密的方法——这类程序仅会破坏用户数据且行为间歇性。若心脏起搏器停止工作,告诉受害者“崩溃时内存并未损坏”不过是徒劳的安慰。我们最近就因unwrap()函数崩溃导致Cloudflare服务中断:
https://blog.cloudflare.com/18-november-2025-outage/
这或许是我抱怨中最关键的一点:Rust是内存安全的,但不可靠。内存安全的代价不仅是开发者的理智,更是可靠性——正因如此我才说语言设计者走得太远。他们为抽象的内存安全原则牺牲了核心实用性。正如Haskell设计者为纯粹性牺牲实用性——这正是我反复强调Rust与Haskell相似性的原因。
4. 可变共享状态
虽然可行,但在 Rust 中使用可变共享状态毫无意义。这样既丧失了Rust的多数优势,又保留了所有缺陷。几乎所有成功的Rust项目都采用共享只读状态、单向数据流、无环数据结构:rustc编译器、mdbook和pulldown-cmark Markdown工具、Actix和Axum无状态处理器、仅追加区块链、单线程WASM皆是如此。这种模式与Haskell高度相似——后者同样擅长解析器、无状态处理器、非交互式命令行工具,并被应用于区块链领域。
Rust早期原型曾采用软件事务内存(STM)实现安全并发,但STM存在性能开销且需要简单却重要的运行时支持。
进入共享可变状态领域——内存损坏并非异常,而是常态。你必须主动处理损坏,而非简单崩溃。借用检查器?所有权?毫无用处,在没有类似垃圾回收的算法时,你无法分析循环图中的所有权关系。
同步/发送、互斥锁和引用计数(Arc)?遗憾的是,这些方案要么加锁,要么严重干扰CPU缓存,因此在多线程通信中效率低下——尤其在高负载场景下。它们虽安全却低效,这几乎摧毁了Rust最初坚持的底线:性能。因此重申:一旦踏入共享可变状态,Rust的所有优势便荡然无存。这其实合乎逻辑——毕竟Rust的核心理念正是杜绝共享可变状态。
尤其需要注意的是,图形用户界面本身就是共享可变状态。正因如此,我们几乎看不到大型Rust图形界面项目。Zed IDE历经多年仍处于测试阶段——我几乎能感受到开发者在借用检查器丛林中艰难摸索的痛苦,最终却发现逻辑漏洞百出,而数十项功能仍待实现。
大型数据库、可扩展的有状态服务、操作系统,至少是重要的Linux模块?尚待观察。
总结
那么Rust究竟是好是坏?其实二者皆非。它只是投入数千人月开发的平庸编程语言——但正因如此,Rust成为可用的工具:你只需从货架上取下它直接使用即可。这篇博客由Rust编写的Zola生成——我根本没写过一行Rust代码就用上了它。Rust之所以适合Zola静态生成器,正是因为其非交互特性与不可变数据的单向流特性。但请别到处嚷嚷“我们都该改用Rust开发,因为它是最佳编程语言”。
本文文字及图片出自 Rust is a disappointment
> 它很复杂。和C++一样复杂。但C++有历史积淀,Rust则没有。每一步都要在
Arc<Mutex<Box<T>>的丛林中艰难前行,这种复杂性直接影响到实现逻辑的质量——换句话说,只见树木不见森林。C++同样存在这个问题,那么最终切换语言的意义何在?暂且不论哪种语言更“复杂”——毕竟这多少带有主观性(尽管我对此确有见解)——但我可以明确指出:我在Rust中编写的绝大多数并发代码并未在每个步骤都使用
Arc<Mutex<T>>(而且我认为自己从未使用过Arc<Mutex<Box<T>>,这相当于在C++中使用std::shared_ptr<std::mutex<std::unique_ptr<T>>>)。认为Rust学习曲线陡峭的观点完全成立,但他们在此处的论证更像是基于个人经历而非普遍现象。所谓“语言转换”的概念更进一步印证了这一点:我编程十年都用Rust,C++是后来才学的。从我的角度看,这等于要从Rust“转换”到C++,同样毫无意义。(我明白自身经历可能不具普遍性,但这恰恰是我的观点所在:每个人的视角都不同,若无法说明为何个人主观体验能代表多数人的普遍感受,仅凭主观经历论证语言的“核心问题”便缺乏说服力——而本文完全未能做到这一点)。Rust确实存在问题,令人不悦之处也不少,但这篇文章让我感觉作者并未真正深入使用过Rust。遗憾的是,针对Rust的批评中此类情况屡见不鲜。
> 内存安全并非至高无上。事实上,对许多应用而言,异常运行比崩溃更可取——尤其在Rust力图进驻的嵌入式领域。你不可能用Rust实现99.999%的可靠性——它总在崩溃。
没错,直到某个内存安全问题引发完全不同代码区域的内存损坏,突然间你就要耗费大量时间调试那些难以诊断的崩溃故障了。
> Cloudflare最近的停机事故就源于unwrap()函数的崩溃:https://blog.cloudflare.com/18-november-2025-outage/
该
unwrap()调用前已发生多次故障,完全可以论证这与未检查异常或发布断言并无本质区别。> 同步/发送、互斥锁和引用计数(Arc)?遗憾的是,这些机制要么加锁,要么严重干扰CPU缓存,因此在多线程通信中效率低下——尤其在高负载场景下。它们虽安全却低效,这某种程度上破坏了Rust的首要原则——性能。
其他语言采用“正确”方式实现是否同样影响性能?我不明白为何Rust强制要求正确实现却引发性能问题,这被视为Rust特有的缺陷。其他语言采用“凑合实现”的方式,即便暂时解除了阻塞,最终也可能反噬自身。
我曾在Rust中多次为快速实现功能而使用
static mut全局变量,结果随着项目规模扩大,意外触发了未定义行为。>没错,直到内存安全问题导致完全不同的代码区域发生内存损坏,你才发现自己正耗费大量时间调试那些难以定位的崩溃。
这确实是极具说服力的论点。不过正如我在文章中暗示的,你完全可以在保持理智的前提下获得大部分保障。内存安全问题固然重要,但绝非应用程序中唯一的问题根源——正如Zed开发者所发现的那样。
>在其他语言中采用“正确”方式也会产生类似影响?我不明白为何Rust强制要求正确做法导致性能问题,这竟成了Rust特有的问题。在其他语言中采用“先搞定再说”的方式,即便能暂时突破瓶颈,最终也可能反噬自身。
这或许违背直觉,但多线程代码中的垃圾回收机制其实能极高效地运作。想象这样一种场景:你随意创建大量对象并建立随机引用,最终由GC自动梳理混乱——在回收周期启动前,整个过程几乎零开销。逃逸分析和语义作用域容器能大幅减少GC工作量(因此不会出现经典JVM GC问题)。更专业的技术如RCU和通用衰减状态回收甚至能实现完全无停顿。
> 这里提出了一些非常有力的论据。不过正如我在文章中暗示的,你完全可以在保持理智的前提下获得大部分保障。
我认为这正是你的文章引发强烈反响的原因之一:你观点的诸多依据都未明言,而你列举的Rust具体示例(如
Arc<Mutex<Box<T>>>>和.unwrap)实在难以避免被视为稻草人论证——毕竟许多人日常编写Rust代码时根本无需依赖这些特性; 事实证明,对于这些开发者而言,完全可以在不牺牲理智的前提下从Rust中获得更高可靠性。你提出的多数观点,其实更像是个人对Rust体验的不满——这种感受完全合理,但不能代表语言的“核心缺陷”。若你只是阐述“为何个人不愿用Rust编程”,我倒不会过多批判(尽管这些理由对我基本不适用)。不过话说回来,这篇文章开篇就承认自己曾刻意发表挑衅性言论,纯粹是为了弥补对他人偏见的感知。也许我正陷入同样的陷阱——试图认真对待这篇文章。
> 我们最近确实遭遇了Cloudflare服务中断,起因是unwrap()函数崩溃
哎呀,这下Rust的批评者们又找到新把柄了吧?
没错,解包`Err`值会引发panic,这并不意外。Cloudflare设置了特定限制来防止内存消耗失控,结果某个错误查询返回了远超预期的数据集,导致内存分配失败。
由此得出两点结论:1) 若Cloudflare未为此类情况设定合理失败模式(即硬编码的备用配置),最终结果仍将相同——大量500错误;2) 大多数程序在内存分配失败时表现并无显著差异。
>有两个结论:1) 若Cloudflare未为此设定合理故障模式(即硬编码的回退配置),最终结果仍将相同:大量500错误;2) 大多数程序在分配失败时行为差异不大。
那么他们为何需要Rust?它提供了什么优势?这正是文章的核心观点——我们都渴望更好的语言,却换来了另一种糟糕的语言。
> 那他们究竟为何需要Rust?它究竟提供了什么优势?
Rust未能在某个具体场景中阻止某次错误,并不意味着它在任何场景下都无法防范任何错误。这同样不代表Cloudflare在其他方面未曾受益于Rust。
例如Cloudflare早前博客[0](重点标注)中提到:
> Oxy为我们提供了性能、安全性和灵活性的强大组合。基于Rust构建的它消除了整类困扰我们Nginx/LuaJIT版FL1的缺陷——如内存安全问题和数据竞争——同时实现C级别的性能。
[0]: https://blog.cloudflare.com/20-percent-internet-upgrade/
难道是为了防范其他潜在的内存安全漏洞——那些此前未引发崩溃的漏洞?
>它的编译速度很慢。我是说非常慢。
D语言在角落里微笑[1]。
“D语言支持所有权和借用机制,与Rust相同。得益于高效的前端和后端,D语言的参考编译器DMD能在5秒内完成自我编译。通过特质和模板,D语言易于实现元编程。借助dynamicCompile,你甚至能用D语言编写自己的即时编译器。”[2]
[1] 凯文·詹姆斯表情包创作者试图解读照片爆红原因:
https://www.yahoo.com/lifestyle/kevin-james-became-internets…
[2] 问答社区提问:既然有D语言可用,为何选择Rust?
https://news.ycombinator.com/item?id=23494490
这类文章充斥着作者主观臆断的空泛论调,必须与更具实证价值的研究相比较——比如Android团队证实相较C/C++语言,Rust能将内存漏洞减少1000倍。感谢你的观点,但我更倾向于采信实际使用该语言的开发者意见。
强烈反对。
以我开发小型项目的实际经验而言,相较于Android团队的意见,我绝对更重视小型项目的实践反馈。
试图模仿FAANG公司的工程实践纯属愚蠢之举,轻则暴露天真,重则沦为简历造假。
安卓团队并未进行同类比较,尽管人们似乎产生了这种印象。
我倾向于持不同意见。
– 编译速度。为何人们如此在意?调试模式用于验证正确性并迭代代码。运行间隔内代码变更甚微,且能实现增量编译。让rust-analyzer在编译前检测错误。让CI在专属时间进行发布优化,谁会在意CI速度慢?
– Cloudflare的漏洞并非Rust所致。所有语言都需要某种机制来标记“此内容无效”,当AI工具列表过长时(或因其他业务问题)就会触发该机制。应用程序进入panic状态是设计选择,而非语言特性。所有语言都有不处理错误的方式。
– 存在 unsafe {…} 并不意味着不可靠。相反,若在 Rust 程序中遇到内存问题,你至少知道该从何处排查。C++ 的问题在于整个程序都处于不安全状态,导致无法定位具体问题。内存安全错误如同类型错误:属于值得检查的大类错误。若你编写的是优质C++代码,本就需要使用检查器进行类似验证;若你足够严谨,更会将警告升级为错误。不过我认为营销过度强调了内存管理,因为许多在Rust中默认实现的硬核经验,在C++中仍是可选项。
– 可变共享状态:让糟糕的设计难以实现。可变共享状态是永恒的漏洞根源之一。请使用通道传递消息。
坦白说,这读起来像许多对Rust的批评:人们尚未投入足够时间,也未跨越学习曲线。当然,在习惯之前一切都会显得繁琐。
> 编译速度。为何人们如此在意?
Ardour是真实世界中的中型项目。约130万行代码,几乎全部采用C++编写。在最快的典型x86_64系统上,编译耗时约1.5分钟;在M3系统上约3.5分钟;在稍旧的x86_64 16核系统上约7.5分钟。
若你修改过libs/ardour/ardour/session.h或libs/pbd/pbd/stateful.h,几乎需要重新编译整个项目。修改libs/temporal/temporal/timeline.h同样如此。这只是原生桌面应用开发者的日常工作——与持续集成或版本发布无关。
这 正是我们关注的原因。
> Cloudflare漏洞并非由Rust引发
没错。Rust的Option::None相当于C++的null。解包Option就像检查变量是否为空并导致崩溃。这种“解包引发崩溃”在其他语言里就是空指针异常/段错误。同样的漏洞在其他语言中编写起来轻而易举,且结果几乎完全相同。只是——因为是Rust代码才显得奇怪。怎么回事?
> 说实话,这读起来像许多对Rust的批评:人们尚未投入足够时间,也未跨越学习曲线。
完全正确。我使用Rust多年,我的抱怨截然不同。虽然我仍希望它能更快编译,但其他问题都是新手才会遇到的。作为资深用户,我的痛点在于:异步块会施展编译器魔法,而你无法自行实现;无法命名的类型令人厌恶;Pin机制既混乱又怪异;与原始指针交互的语法既笨拙又丑陋。
没错,Rust让涉及大量共享可变状态的程序难以编写。所以别那样编程。总的来说,若你用语言X编写代码时,却把它当作语言Y的劣质版本来用,那你注定会吃苦头。关键问题在于:采用“Rust式”的代码设计思维能否造就优雅的程序?若你带着太多关于程序设计应如何的先入之见,是无法回答这个问题的。
作者声称“Rust频繁崩溃”,并援引Cloudflare的unwrap()事件作为例证。呃…但这显然是程序员失误吧?忽略Result可能返回Err而非Ok的情况,本就不在语言的保护范畴内。
巧合的是,我本周末刚与Cloudflare工程师交谈过†,他们辩称问题本身不在于unwrap()函数,而在于跳过数据验证步骤就从“无法确定数据有效性”直接推断为“系统彻底崩溃”——这种思维模式无论每分钟执行一次还是每月执行一次都同样错误。
我反驳道:强制使用expect(“预期值”)而非unwrap()能培养编写者思考预期结果的纪律性,从而明确为何无需触发panic——这要求在expect调用中明确定义预期文本。但他们并未被说服,依然坚信Cloudflare需要的不是改进工程实践,而是更严格的部署纪律。
† 他们恰巧在Cloudflare工作纯属巧合,而我周末大部分时间都和他们在一起则是刻意为之——我们当时在玩电子游戏。
没错,但在C++中我们根本不会断言has_value是否成立,而是直接返回隐含的内存损坏。或者说,我认为这是作者的论点。(我并不认同这种观点。)
是啊,如果作者真想表达这个观点,我实在无法理解这种论述。若存在某种语言能让程序员的错误不产生恶果,C++绝非其一。因此该论点要么需附加“C++程序员水平更高”的论断(这本身已是需要证据支撑的大胆主张,且已偏离语言本身),要么就不能算作针对Rust的有效论据。
确实存在崩溃后能恢复的编程语言/模型/运行时,也存在能优雅降级的模型。但Rust无法恢复。C++在许多情况下同样如此——例如析构函数中抛出异常时,必然会触发
std::terminate。需注意C语言本身并未内置此缺陷——这是C++设计者创造的缺陷,而Rust继承了这一缺陷(设计者根本不认为这是缺陷)。我指的是专门设计的嵌入式C代码能在内存完全损毁时(只要CPU寄存器和ROM完好)仍执行有效操作。或对比BEAM虚拟机:即使进程全天崩溃,系统仍能持续运行。“不惜一切代价保障内存安全”并非实用需求——这是宗教信仰。
> Rust无法恢复。
> 抛出异常时,销毁函数必然触发
std::terminate。> 例如销毁函数中抛出异常时,必然触发
std::terminate。你 可以 在析构函数中抛出异常[1]。只需将该析构函数标记为noexcept(false)。但若异常在析构函数 已开始展开时 逃逸,确实会触发std::terminate。
> 需注意C语言本身并未内置此类缺陷
assert() 向你问好?
> 我的意思是,经过特殊设计的嵌入式C代码能在内存完全损毁时(只要CPU寄存器和ROM完好)仍执行有效操作。
为何类似论点不能适用于“特殊设计的”Rust?
> 或者对比BEAM内存管理——即使进程持续崩溃,系统仍能正常运行。
重申:没有任何因素阻止你编写能实现相同效果的Rust代码。
[0]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
[1]: https://cpp.godbolt.org/z/ao4cf3zrr
在Rust中引发panic的强制性,与在C中强制调用abort()并无二致。
在概念上与以下代码并无二致:
若不想导致程序终止,请避免编写这两种代码。
Rust的最大价值在于规避海森堡错误https://en.wikipedia.org/wiki/Heisenbug
内存安全与线程安全是海森堡错误的诱因,但并非唯一成因。Rust无法捕捉所有此类错误,但不完美并不等于无用(完美解决方案谬误)。
该文虽有合理观点,却充斥着煽动性夸大。
> 该文虽有合理观点,却充斥着煽动性夸大。
考虑到针对Rust的批评往往缺乏证据支撑,这篇还算不错。
如今LLM技术让C语言更易上手,Rust在许多场景已不再必要。
这要么是行为艺术要么是愤怒诱饵。文中观点荒谬至极,诸多论断既错误又离奇,不知该从何说起。
可变共享状态是特性而非缺陷。
诚然,使用不可变共享数据或非共享数据编写正确的异步代码更容易。
然而,若没有可变共享状态,实现快速且低内存消耗的并发算法几乎不可能。
我不知道,但通常经验法则是:算法中可变共享状态越多,其可扩展性越差。因此若试图将系统并发化,可变共享状态实为反模式。
如前所述,真正导致扩展性问题的是锁竞争而非可变共享状态。无锁数据结构、RCU等模式…在多数场景下都能完美适配具体需求。许多需要高可扩展性可变共享状态的场景,其数据使用模式存在固有不对称性(例如单写多读、多读单写),这类场景几乎总能找到比“用互斥锁包裹”更优的解决方案。
不,问题根源在于可变共享状态本身。锁竞争只是可变共享状态引发的下游问题。
> 诸如RCU之类的模式
RCU并非可变共享状态!它共享的是不可变状态!这才是整个范式。
锁竞争才是导致速度下降的主要因素。
但实际情况往往取决于具体场景。
最优算法会智能划分操作对象,避免争用。例如处理矩阵时,可将其分割为可并行处理的子块。
> 锁争用才是导致速度下降的首要因素。
本质上都是同一问题的不同表现形式。锁竞争之所以耗时,是因为核心间共享可变状态本身效率低下——这都归结于~MOESI机制。
> 最优算法会巧妙划分共享数据,避免竞争发生。例如处理矩阵时,可将其分割为可并行处理的子块。
没错。即采用零共享或只读共享状态模式。
作者用Zig编程应该会很开心。
我个人对Rust最大的不满是可读性不足。见过某些函数签名简直像直接从C++搬过来的。
> 我个人对Rust最大的不满是可读性不足。见过某些函数签名简直像直接从C++搬过来的。
这永远是权衡取舍。若没有当前签名形式,编译器确实无法获取足够信息。当信息压缩到一定程度时,必然会牺牲某些特性。
创建类型别名始终是个选项,但这样做难免有“拆东补西”之嫌。
虽然签名变短了,却剥夺了程序员快速理解代码行为的能力。
你不能抱着“我写的是冷路径高阶代码,不需要性能优化,不必深究生命周期管理,只想实现高阶逻辑”的态度行事。每次书写Rust代码时,你都将被迫面对底层细节。Rust没有垃圾回收机制且永远不会有——你必须半手动地将所有数据封装到所有权树中。仅写几行代码就需要精通所有权、借用和特质机制。
虽然仍显粗糙,但Crystal是此类场景的有趣选择。若你追求可读性强的抽象语言、理性的包管理器,以及能编译为高效机器码的特性,值得一试。
Crystal、nim、zig的问题在于它们毫无发展壮大的可能。
Crystal和nim大概率不会。
Zig…尽管语言状态尚不成熟,实际使用率却出人意料地高。这让我认为若它能达到v1.0版本,极有可能至少成为“Kotlin”级别的语言,甚至有望达到“Elixir”/“Haskell”的高度,成为“TypeScript”的有力竞争者。
本以为作者会为自己偏好的技术辩护,结果只是在发牢骚
打造更优解决方案绝非易事。作为应用程序开发者,我想问“为何不直接用Java/C#?”——甚至要说Java背后的软件复用革命并非源于面向对象特性,而是垃圾回收机制。
换言之,在C/C++/Rust中构建预制组件的应用程序充满挑战,因为内存管理本身就是API的一部分。C开发者极度重视内存分配控制权,他们希望在库中复用应用程序的缓冲区,或让库在应用程序管理的内存池中分配资源等等。这种复杂性使得库无法合理支持应用开发者期望的所有场景,最终陷入困境——因为释放内存时,应用程序必须知道库是否已完成使用,或者库必须知道应用程序是否已完成使用…… 然而, 垃圾回收器知道! 。最终,许多库无法真正为C语言编写,即使能编写,也必须假设应用程序按特定方式分配内存,否则就会失去C语言声称赋予的内存控制优势。
反观C语言,某些场景下它反而过于高级。例如嵌入式C或设备驱动的编写过程常被视为常态,但许多操作用汇编语言实现会更简洁。我曾为AVR-8编写过体积很小的程序,却因C语言在栈指针上的频繁操作和遵循的调用约定而抓狂——这些对特定程序而言完全没有必要。
我有朋友在IBM大型机领域工作,那里至今仍常见应用程序包含汇编语言代码——为追求效率或获得比COBOL更精细的控制权。COBOL的难题在于:你必须是宏汇编程序员才能处理这类代码,且无法直接将其移植到Linux上的GNU COBOL环境,除非同时移植汇编部分!
我们仍身处多架构时代,因此试图简化汇编编写(想象一个集成定理证明器的超级宏汇编器)的构想根本行不通。让x86架构再挣扎十年,若RISC-V毫无进展,几年后局面或许会改变。
> 对受害者说“但崩溃时内存并未损坏”是种苍白的安慰。我们最近就因unwrap()函数崩溃导致Cloudflare服务中断。这恰恰印证了我抱怨的核心:Rust虽内存安全却不可靠。内存安全的代价正是可靠性
这种说法在某种程度上简直令人感到侮辱。你调用
crash()函数并非语言的过错——所有语言都有终止执行的机制,且存在合理依据。崩溃本身未必是错误行为;这是将错误传递至基础设施层处理的方式。问题根源在于系统设计层面,而非语言层面。作者将这种(糟糕的)批评改写为:
> Rust无法实现99.999%的可靠性——它总在崩溃。
这种表述对我这个读者而言,简直是赤裸裸的不诚实与侮辱。
为什么要把crash()函数命名为“unwrap()”?感觉很奇怪…
那Ada呢?
关于页面的博客很有意思:
> 人们编造谎言以获取权力和金钱。这本该是我的人生轨迹,但出于某些随机原因,我叛逆地选择了理智。
> 我反虚伪。
这种“为反对而反对”的气息自然渗透到这篇Rust文章里。Rust确实问题不少,但这篇批评实在太肤浅。
编译速度慢我能接受,比C++慢也无妨,但大型项目真需要超过32GB内存吗?比如LLVM、Chromium或Envoy这种情况?
为此不得不买新笔记本。
> 写几行代码都得精通所有权、借用、特质机制
> Rust为内存安全牺牲了理智与实用性
技术问题
> Node.js和Go被视为实质安全的语言
Node JS过去存在漏洞:https://www.cvedetails.com/cve/CVE-2021-22940/
Go语言同样不具备内存安全性:https://www.ralfj.de/blog/2025/07/24/memory-safety.html
Node.js和Go都具备内存安全性,Python、Ruby和Java亦然。“内存安全”是技术术语,指普通开发者编写的代码是否易受内存损坏漏洞影响。几乎所有试图证明Go或Python等语言存在内存安全隐患的案例,都是程序员刻意钻语言漏洞所致。但这种操作在任何语言中都可能发生,包括Rust。
本质上仅有两种主流内存不安全语言:C和C++。
我在Go中遇到过内存问题,但在Rust中(目前)尚未遇到,因此对此观点持异议。在Go中触发这类问题其实并不困难或晦涩。
构建并发系统时,Go语言极易引发内存损坏,根本无需掌握任何“规避语言机制”的技巧。
“内存损坏漏洞” ≠ ‘并发缺陷’,甚至不等于数据损坏。上次讨论这个话题时,有人拿Go的段错误举例说“看!内存损坏!”(显然不是)。
对此类论调的简单回应:当前已有海量Go代码库,包括整个K8s生态系统。请展示内存损坏的实际利用案例。
对于以安全为核心的语言而言,Rust中大量使用unsafe是重大隐患。同样的质疑也适用于Go的unsafe关键字。
存在专门检测依赖项中unsafe使用的crates,恰恰说明该关键字被相当宽松地使用。Geiger就是典型例子。
在Go这类语言中,unsafe的使用极为罕见,主要因为开发者很少深入底层系统来追求极致性能。
含unsafe的Rust代码:170万
含unsafe的Go代码:40万
而Go的仓库总量约为Rust的2.3倍。因此Rust中unsafe关键词的使用量约是Go的10倍。
这其实和
unsafe几乎毫无关系。作者提到这点后收获大量反对票。任何涉及Rust的话题都如此典型。
我没有给你点赞,也不可能点赞(你是在回复我)。
请不要在评论区讨论投票事宜。这毫无益处,只会让阅读变得乏味。
https://news.ycombinator.com/newsguidelines.html
我同意,基于这个原因我个人不会称Go语言为内存安全的语言。Thomas的半定义包含“漏洞”一词,这极大缩小了适用范围——Go语言恰好符合标准,因为常见的数据竞争导致内存损坏的情况,在非人为构造的场景下尚未被证明可被利用。
我个人对Go这类语言内存安全的定义是:除非显式调用unsafe,否则无法引发此类内存损坏——但目前尚无权威定义可供参照。
每当论坛讨论专业术语时都会出现这种情况。就像“零信任”概念引发的漫长模糊辩论——人们纠结“信任”的定义,但该术语本质上仅指摒弃传统边界网络架构。抱歉,但在行业实践、ISRG规范及政府指南中,该术语 特指漏洞 。
> “图灵机模型中根本不可能存在完美的正确性”
哼。无知者总爱这么说。程序验证已有四十余年历史,对大多数实用程序而言,通过不违反断言来实现形式正确性是完全可行的。正如有人针对微软静态驱动程序验证器所言:若程序涉及任何不可判定性,就不该出现在内核中。这并非正当批评。
> 若程序涉及任何不可判定性,就不该出现在内核中。
谁他妈在乎什么“内核”(无论哪个内核)?我编写的原生桌面应用程序完全无法验证。
定理证明器的理念影响了Java、Rust及众多语言——若能实现更突破性的成果将非常棒……若能让程序与正确性证明并存就太好了。
我理解的是bykozy在说“Rust内存安全但不可靠”,因为Cloudflare因未处理异常而崩溃??
我曾是Rust程序员,做了三年。做过Web后端、内核编程、网络安全…
后来发现C++有个Rust没有的超酷特性:任务(jobs)。
现在我不再搜索Rust职位了。
> 遗憾的是,Rust无法实现快速编译。这是所有泛型密集型语言(如Haskell)固有的问题。
严格来说,我认为这种说法并不准确。此外,我认为这混淆了泛型编译缓慢的两个常见原因:
– 类型检查可能耗时巨大
– 泛型实现方式可能产生大量代码
泛型密集型语言并不必然具备这两点(例如OCaml尽管拥有“复杂”的类型系统,仍被公认为编译速度快), 且两者并不必然关联——假设存在一个大量使用单态化的“简单”泛型系统,其编译仍可能耗时;而采用类型擦除的“复杂”泛型系统,类型检查可能较慢,但后续编译却可能很快。
> 在其基础上添加强制性的借用检查器
据我所知,借用检查器通常仅占编译总时间的极小部分。虽然存在例外情况,但我认为人们往往高估了它对编译时间的影响。
> 存在既能实现不安全程序,又不会执行远程代码或泄露机密的方法——这类程序仅会破坏用户数据并间歇性异常运行。
要 可靠地 实现既无远程代码执行漏洞也无机密泄露,却仍能破坏数据且“间歇性运行”的不安全程序,在我看来是种非常奇特的组合要求——即便这种组合真的可行。“间歇性运行”本身定义模糊,具体问题可能实为隐藏的远程代码执行或机密泄露——毕竟漏洞利用往往始于用户发现程序崩溃,这种情况并不罕见。
> 这或许是我抱怨的核心:Rust兼具内存安全与不可靠性。内存安全的代价不仅是开发者的理智,更是可靠性本身
我认为这恰恰是最薄弱的论点。我未见任何证据支持“内存安全必然以可靠性为代价”的论断,更遑论Rust正是如此。
> 进入共享可变状态——在那里内存损坏并非例外,而是常态。你必须处理损坏情况,不能简单地崩溃。
这里使用的“内存损坏”定义是什么?我以为这种情况通常不需要“处理”…
> 这某种程度上破坏了Rust最核心的特性——性能。
我觉得这误解了Rust的优先级。(安全的)Rust始终将安全性置于性能之上,这种权衡在其整个发展历程中都是众所周知的。若想牺牲安全性换取性能,`unsafe`正是为此而生。
> 因此重申:一旦踏入共享可变状态,你就丧失了Rust的所有优势。考虑到Rust的核心理念正是杜绝共享可变状态,这种设计其实合乎逻辑。
这忽略了Rust另一项实用特性:可将不安全性明确限制在代码库的特定区域内。
本可详述更多,但生活在召唤…
> T, T&, T*, std::optional, std::unique_ptr 描述类似概念,各自存在独特缺陷
`T` 哪里有缺陷?其他特性又存在哪些缺陷?
无论使用何种语言,你编写的代码与硬件之间运行的绝大部分代码都将由 C 语言实现。你对顶层 1% 代码的选择影响甚微。无论如何,攻击面依然巨大。
>它的编译速度很慢。我是说非常慢。比C++还慢。我知道这些年Rust速度提升了数倍,但客观上我们需要它快两个数量级,而非仅仅两倍。
重构你的构建流程。
>它很复杂。和C++一样复杂。但C++有历史积淀,Rust没有。每一步都要在
Arc<Mutex<Box<T>>的丛林中艰难前行,这种复杂性直接影响实现逻辑的质量——只见树木不见森林。C++同样存在这个问题,那么最终切换语言的意义何在?若你有更优解,大可编写宏实现。
>内存安全并非神圣不可侵犯。事实上,对许多应用而言,异常运行比崩溃更可取——尤其在Rust志在进驻的嵌入式领域。Rust无法实现99.999%的可靠性——它时刻都在崩溃。
深入学习语言特性,运用代码覆盖率工具,编写更完善的测试。
>处理大量可变共享状态(GUI、数据库、有状态服务、操作系统/硬件)时,Rust原生内存模型的性能表现欠佳,而非原生的unsafe操作只会带来编译缓慢、复杂度高且最终仍无法保证内存安全——这使得Rust在处理重度可变状态任务时几乎毫无意义。
C++若实现不当同样如此。
完全错误。
> 它的编译速度很慢。我是说非常慢。比C++还慢。
不可能。或许Rust 1.0是这样,但它一直在改进,现在绝对比C++快。
> 它很复杂。和C++一样复杂。
确实如此,但C++复杂性的问题在于你必须记住所有细节,否则就会意外触发未定义行为。这种复杂度几乎让人无法完全掌握。
Rust确实复杂,但大多数情况下编译器会提示错误。当然存在例外(大量异步陷阱),但两者仍天差地别。
> 内存安全并非至高无上。事实上,对许多应用而言,异常运行比崩溃更可取
这个观点无需反驳…
> 当处理大量可变共享状态(GUI、数据库、有状态服务、操作系统/硬件)时,Rust原生内存模型的性能表现欠佳,而非原生的unsafe操作只会带来编译缓慢、复杂度高,最终还无法保证内存安全——这使得Rust在处理大量可变状态的任务时几乎毫无意义。
此处论点稍显模糊。或许指GUI编程的易用性尚待完善?但这绝非致命缺陷吧?众多C/C++ GUI库的易用性同样糟糕,而唯一真正优秀的Qt库,数十年来都依赖自定义语言扩展才实现其卓越体验。
> 那么Rust究竟好坏?它两者都不是。这只是个平庸的编程语言,耗费数千人月开发而成
真想听听他心目中优秀编程语言的标准,因为我能轻易找出比他列举的更多其他语言的缺陷。
这种反Rust狂热实在令人厌烦。
他对C++的厌恶程度几乎和对Rust一样。你的论点似乎是Rust优于C++,这好比试图论证霍乱比天花更优越。
语言之争既无趣又无意义,每种语言都有糟糕之处。正确做法是根据具体任务选择相对最不糟糕的语言。
> 真想听听他心目中理想的编程语言是什么样
虽然不是楼主,但除极端性能敏感的软件外,我更倾向Swift、C#或Python。
C#确实很优秀,但Swift作为真正适用于所有平台和操作系统的通用语言是否足够好?
> 真想听听他心目中优秀编程语言的标准
虽然不是楼主,但我敢打赌他会选Python。
– 无编译时间
– 不如C++复杂
– 内存安全机制(虽然他们似乎不在意,但有总归好)
– 丰富的图形化开发工具,如PySide(Python版Qt框架)
当然Python缺点不少,比如解释型语言运行缓慢,鸭子类型更甚…但这并非楼主抱怨的重点。
该文抱怨Rust程序调用
unwrap时可能崩溃——事实上作者称这是其最严厉的批评。而Python调用sys.exit时同样会崩溃,所以两者并无优劣之分。遗憾的是我认为这种批评缺乏逻辑——这根本是荒谬的标准。
现代C#相当出色,性能同样可观
用D吧。
没错,不过是又次数据泄露,小事一桩。
朋友之间执行点任意代码又何妨?
我的意思是没有比Rust更好的语言,与其这么说不如讨论Rust的哪些特性令人困扰
除非需要近乎100%的内存安全且不牺牲性能,否则我更倾向于用Zig、Odin或Go编程。
Zig和Odin编写体验更愉悦,能满足多数应用的安全需求;Go则能提供接近Rust 90%的性能,却没有那么复杂。
我们似乎正式到达了转折点——Rust的反对者比拥护者更令人烦躁了。或许再过几年,我们终于能停止为此写博客了。
"总结:
那么Rust究竟好坏?其实二者皆非。它只是投入数千人月开发的平庸编程语言——仅凭这点就足以成为实用工具,毕竟它能直接拿来即用。这篇博客由Rust编写的Zola生成——我根本没写过一行Rust代码就用上了它。Rust与Zola静态生成器(SSG)高度契合,因为它具备非交互特性和不可变数据的单向流。但求各位别到处嚷嚷'我们都该改用Rust开发,因为它是最佳编程语言'。"
这难道就是所谓的Rust黑?
整篇文章除了最后总结都在贬低Rust。
老兄,我在开篇第一句就说明了——它并非糟糕,而是远比本应达到的水平差得多。文章主体并非恶意——只是陈述事实。所有参与重大Rust代码库开发的人都认同:Rust编译耗时漫长。复杂性?我认识喜欢复杂性的人,他们会说“正因编程难度高,这才是伟大语言!”——对他们而言复杂性反成赞美。共享状态?“别用就是了,你用错了”。以上就是全部,何来仇恨?
> 文章主体并非恶意攻击——只是陈述事实。所有参与大型Rust代码库开发的人都认同…
笑死。这根本不是事实。你不过是把使用Rust时遇到的挫败感,包装成“关于这门语言的深刻真理”罢了。你不能代表Rust社区发声。若你只谈个人经历而不将问题泛化,这篇文章会有趣得多。
关于编译时间:2024年Rust现状调查显示,25%的开发者认为缓慢构建是重大问题。这可是相当多的人!但19%的人表示完全不存在此问题。显然并非“所有人”。
https://blog.rust-lang.org/2025/02/13/2024-State-Of-Rust-Sur…
我怀疑如果你持续使用Rust,那些让你恼火的特性会随着时间大幅改变。有些问题不再困扰你,而有些问题反而会变得更烦人!(比如我认为Rc/Box等机制其实无关紧要。一旦学会用Rust式的方式组织代码,这些东西几乎就派不上用场了。)
如今我真心喜爱Rust。但当初学习过程极其痛苦,完全理解你的挣扎。但请别把个人困境当成Rust的普遍真理——你只是其中一员。
主观感受(永恒性、复杂性等)永远无法成为事实依据。你的帖子虽有事实依据,但听起来仍充满偏见。
从整篇文章来看,结论相当明确。
绝非如此。Rust拥趸们依然像往常一样喋喋不休。Rust的反对者越多越好。
你能举些例子吗?C/C++开发者似乎对Rust的内容非常不满。那些烦人的文章都去哪儿了?那些声称我们应该用Rust重写所有代码的文章?既然C/C++开发者如此愤怒,这些文章肯定铺天盖地。但我好像没读过任何一篇?
安卓团队那篇关于Rust如何优化开发流程的文章[1]算吗?你指的是这个?那篇文章让你 情绪上感到不适 ?希望它没写出来?具体哪里让你不爽?是想让人停止写技术文章来保护你的感受吗?
[1] https://news.ycombinator.com/item?id=45918616
一年多没见正面评价Rust的文章登上HN了。看来时代潮流已转向反对它。或许美国政府亮出支持态度就是转折点吧。
另一方面,我们必须承认:IT系统中安全性的优先级往往最低。毕竟在快速交付、快速迭代、性能优化、兼容性保障、架构稳健性(无论具体指什么)、便捷测试、带UML图的文档、精心设计的接口之后——安全性问题可能只被塞在某个遥远抽屉的最底层。人们总是在安全漏洞摧毁整个业务后才谈论其重要性。
我们需要加强安全防护,但恐怕不需要Rust语言。
安全事件摧毁企业的案例极其罕见,安全漏洞的处罚更是形同虚设。因此尽管人人高呼“安全至关重要”,在绝大多数情况下它其实并不那么重要。比如该死的Experian——这家以收集保护全民数据为存在意义的公司,竟泄露了所有人的数据,结果大家反应是“哦,行吧,继续吧…”
> 讨厌Rust的人比Rust传教士更烦人
我不认同。对我而言,距离那个转折点还有很长的路要走。
至少Rust传教士们能做出实用的东西。
真正能干成事的人根本没空传教。
> 请注意二叉树如今基本属于过时的遗留技术——它们对缓存极其不友好。其实用C++的std::vector或std::dequeue就能实现类似功能,还能获得边界检查。
正如某条评论所言,这其实是B树而非二叉树。据我所知,B树在现代计算机上处理特定问题时堪称最快的数据结构。
没错,如果我重返C/C++领域,定会尝试这种方法。它在JS/TS/C#/Go这类GC语言中同样可能表现出色,毕竟需要管理的指针更少。
> Cargo在包数量少时表现良好。但大型项目已面临单次构建中存在五个版本serde的困境,还需依赖Cargo自身无法构建的FFI关联库。看看NPM的噩梦吧——他们基本避开了FFI问题。
我虽未遇过“五个版本serde”的问题,但完全能想象其严重性。我经历过的NPM噩梦多到数不清。但比起CMake、autotools和Makefile带来的所有问题,我仍更倾向于NPM。照这样下去,我们恐怕要等到自动驾驶汽车问世,才能拥有一个像样的C语言构建系统。
> 请注意二叉树如今基本属于过时的遗留技术——它们对缓存极其不友好
BTree并非二叉树,而是B-树,且具备缓存友好性
> C++20通过概念特性基本复现了特质功能
C++20概念与特质截然不同。概念是结构化的,使用起来笨拙;而特质是名义化的。两者还存在其他重要差异。
我们真正需要的,是官方/诚实的Rust指导文档,明确哪些方案可行哪些不可行。经典案例就是如何规避循环数据结构的问题。
简而言之:Rust不支持任何形式的循环数据结构,除非使用间接引用或unsafe。间接引用工具链功能薄弱,多数实际案例直接转用unsafe模式。只要精通内存操作,在这些场景下使用unsafe完全可行。
还有几个需要明确的陷阱,其中有些会限制高级软件开发,有些则不会(如字符串处理)。若能驾驭unsafe,Rust工具链远胜C/C++开发环境,堪称我们能获得的最接近理想的替代方案。
几年前我曾为某个项目用几千行不安全Rust代码实现了一棵B树(严格来说是序统计树)。其实现方式基本沿袭了C语言的思路:每个内部节点和叶节点都单独分配堆内存,内部节点还包含子节点指针数组。编写过程出乎意料地困难且复杂!
在我看来,Rust的不安全代码比C更难使用,因为它缺少箭头运算符。而且即使在不安全代码中,Rust仍强制要求遵循严格别名规则。这使得复杂的不安全代码极难正确实现——代码看似正确运行良好,但MIR仍会发现细微问题。
最终我基于Vec重写了B树。节点与叶子指针现在都用数组索引替代。结果如何?不再存在任何不安全代码。代码显著简化,运行速度竟比之前快了约10%,这令我震惊。看来在现代计算机上,边界检查的开销确实比内存碎片化更低。
完成改写后我产生诸多思考。首先,这才是Rust的正确编程方式。诚然,手动追踪数组槽位的使用状态确实不便。但Rust中的unsafe与指针同样不便——这种编程方式可能导致内存释放后使用错误。不过按Rust的定义它仍是内存安全的:由于不存在原始指针,任意堆内存损坏不可能发生,且索引始终经过边界检查。
我认为生成的代码质量并不逊于等效的C++实现。众人皆谈内存安全,但在我看来Rust最出色的特性在于枚举、性状、Cargo、匹配表达式等。即便绕过借用检查器时,正是这些特性让我不断回归Rust。
我认同更完善的指导会更好,但关于Rust的讨论早已铺天盖地。诸位是否愿意阅读探讨此类细微问题的文章?有时唯一的学习途径就是亲身实践。
最终我将B树重构为基于Vecs的实现。节点与叶子指针现在都用数组索引替代。结果如何?不再存在任何不安全代码。代码显著简化,运行速度竟比之前快了约10%,这令我震惊。看来在现代计算机上,边界检查的开销确实比内存碎片化更低。
在Rust中优化机制极其复杂且可能脆弱,LLVM需要处理海量生成的中间表示(IR),因此原生Rust结构体可能更适合编译优化。尤其值得注意的是,Rust能够优化掉部分边界检查。
需注意二叉树如今基本属于过时的遗留结构——它们对缓存极其不友好。其实用C++的std::vector或std::dequeue也能实现类似功能,同时获得边界检查。
>人人都在谈论内存安全,但在我看来Rust最出色的特性是枚举、特质、Cargo、匹配表达式等
C++20通过概念特性基本复现了特质系统,C++17借助std::variants实现了枚举/标记联合体。匹配表达式确实是C++无法企及的。
Cargo的优势在于包库规模尚小时。大型项目已面临单次构建需管理五个版本serde的困境,更受制于依赖FFI连接库——这些库本身无法通过Cargo构建。看看NPM的噩梦就知道了——他们基本避开了FFI。
不必担心,很快又会有新技术来填补炒作/厌恶周期的空缺,带来新的无谓争论。
Zig目前正处于炒作周期,就像Rust/Ruby/Lisp等语言曾经经历的那样。终有一天新事物会出现,届时Zig就会进入厌恶周期。
实际上这些技术根本不需要反复上演的宗教战争。这不过是程序员中心化社区发展过程中,极其不幸又令人恼火的常态罢了。
可悲的是某些话题早该终结,人们却仍在热议:ORM、OOP、Git、JavaScript臃肿、Linux与Windows之争。
总有新人天真地以为这些讨论仍具价值,或有人会真正关心这些话题。
>ORM、OOP、Git、JavaScript臃肿、Linux与Windows之争
ORM和OOP的抱怨确实小众,同意。Linux与Windows之争已无意义——如今Windows都能运行Linux了,我几乎没见过相关文章。
Git?好吧,现在大多被那些不继承原始Git实现、却冠以“git”之名的解决方案取代了。
JavaScript臃肿?这绝对仍是热点话题。我可不记得它被解决了,你呢?比如打开网站时弹出窗口,要求为网站上300个追踪器应用Cookie政策——这难道不值得讨论吗?
[已删除]
这完全不像AI生成的文本。语法错误频出,句子支离破碎,完全是论坛帖子的风格。
你为什么这么认为?
因为它采用了与大型语言模型相同的结构。至少存在这样的理由——在你真正尝试阅读这篇文章并意识到大型语言模型目前还写不出这样的文本之前。当然,这种结构也适用于我经常阅读的科学论文,所以我确实倾向于遵循这种风格。“具备科学论文形式却表述不严谨=AI粗制滥造”——这就是暗含的论调。
趣闻:Qwen认为我的文章是LLM生成的原因之一,竟是它认定文中链接不可能存在。我被洗脑到打开文章点击链接——结果链接有效。震撼全场。
列表、破折号、标题和LLM典型响应长度。
没错,这篇文章是用Markdown写的,LLM也使用Markdown格式。但这不是LLM的典型响应长度——它比常规长篇LLM响应长约1.5-2倍。不过人类确实不易察觉差异。
我虽不同意你的文章观点,但这篇评论实在荒谬。我也用Markdown写作,在合适处使用列表,甚至——天哪!——在需要时使用长破折号。
你以为AI会写出 “那么Rust是好是坏?它两者都不是。这只是个平庸的编程语言,耗费数千人月开发——仅凭这点就让Rust成为可用工具” ?才不会呢。
我百分之百确定生产过程中用了大型语言模型,只是没直接照搬。
生产环节百分之二百用了大型语言模型——写文章前花了十小时对话。我与Rust狂热粉丝的对话耗时更长,却基本是浪费时间——他们根本不愿就Rust的弱点进行讨论。仅靠人类协助我绝对写不出这篇文章。不得不承认LLM才是更优秀的助手,因为它们保持着中立客观的立场,这实在令人遗憾。
很快我们得这样写了,或许还得加入தேவையே இல்லாம等语言,免得人们立刻断定是AI所作。
之所以说是挑衅性内容,是因为它更像煽动而非真诚。
以下是引言部分的例子:
> 它的编译速度很慢。我是说非常慢。比C++还慢。我知道这些年来Rust的速度提升了好几倍,但客观上我们需要它快两个数量级,而不是仅仅快两倍。
我用过大量C++和Rust,日常增量编译时Rust速度快得多。C++受头文件包含问题困扰,模块功能形同虚设——根本无法实际使用。
>
Arc<Mutex<Box<T>>>这段代码故意设计得极其复杂,根本没必要用Box包装。
> Rust根本无法达到99.999%的可靠性——它总在崩溃。
这话到底什么意思?
>我用过大量C++和Rust,日常增量编译时Rust的速度远超C++。C++饱受头文件包含问题困扰,模块机制形同虚设,根本无法实际使用。
这完全取决于编译对象。我曾用C/C++从零编译5万行代码仅需10秒——Rust恐怕做不到。公平地说,该项目头文件经过了编译速度优化(虽非“极致”但“相当可观”)。人们忘了C/C++在每个模块不包含10个Boost库时能有多快。
>这故意设计得过于复杂,根本没必要存在那个Box。
Arc<RwLock<Option<T>>>——现在听起来不错?别误会——C++同样可能糟糕透顶,但Rust将其固化为规则,强制你只能这样编写程序。>这到底是什么意思?
我上面已解释过,但可以重复:有些运行时模型允许崩溃后恢复,有些模型崩溃后只能勉强运行。Rust只有一种崩溃模式:直接崩溃。
> 我怀疑在Rust里做不到。
你 绝对 可以做到。需要注意结构设计,且并非所有代码库都同样适合这类技术,但这些特性与C++是共通的。
正如你所言:“这完全取决于你编译的是什么。”
> 在 Rust 中只有一种崩溃模式:直接崩溃。
未必。否则为什么会有 catch_unwind 存在?
我认同这是在挑起争论的论断。
“它们仅破坏用户数据且行为随机”
作者轻描淡写地否定这些缺陷,但试着告诉金融机构:当账目无法平衡时,这“仅仅是”用户数据损坏。向航空航天公司解释随机行为完全没问题。
这恰恰是作者的核心观点。