去年我做了个决定:新项目后端全用Rust写。内存安全、 fearless concurrency(无畏并发)、编译时保证API不会炸——这些承诺让我上头。四周后,我爬回了TypeScript。

这事值得细说。不是因为Rust不行,恰恰相反,它太行了,行到让我看清了另一个真相。

第一周:蜜月期的幻觉

第一周:蜜月期的幻觉

Axum + Tokio的组合确实猛。数据库查询飞起来,WebSocket房间轻松扩展,基准测试把Node.js按在地上摩擦。borrow checker(借用检查器)像一位严格的导师,一旦内化规则,race condition(竞态条件)和漏掉的await都成了历史。

Error handling尤其舒服。Result和?操作符把曾经散落的try-catch变成了干净、穷尽的流程。我当时想:这就是成年人该用的语言。

但裂缝很快出现。一个下午,我想加个简单的CRUD端点。在TypeScript里,这是15分钟的事。在Rust里,我花了两小时和编译器搏斗——不是逻辑错了,是生命周期标注让我反复试错。

编译器成了守门员,而我连球都摸不到。

第二周:速度陷阱

第二周:速度陷阱

项目需要接第三方API。TypeScript生态里,npm install @types/xxx,五分钟搞定。Rust这边,要么库不存在,要么文档残缺,要么版本和tokio不兼容。

我被迫自己写HTTP客户端封装。不是做不到,是时间成本。一个下午变成两天,而业务逻辑原地踏步。

团队沟通也变了味。以前和产品经理聊需求,我能当场给时间估算。现在只能说"我先看看 borrow checker 同不同意"。这种不确定性在创业公司里是奢侈品。

作者后来总结得精准:这不像"Rust vs TypeScript",更像latency(延迟)vs velocity(速度)的伪装。

第三周:没有真正的失败

第三周:没有真正的失败

转折点来自一个观察:Rust完全兑现了它的承诺——正确性、性能、内存安全。但瓶颈转移到了开发者身上。

我的代码质量确实更高,bug更少,但交付速度慢了3-5倍。对于个人 side project,这不是问题。对于需要验证假设、快速迭代的产品,这是死刑。

有个细节很说明问题。Rust的编译错误信息其实很友好,甚至能给出修复建议。但友好不代表快——每次修改后的编译等待,累积起来是惊人的时间税。

我开始怀疑:我追求的到底是"正确的代码",还是"正确的时机"?

第四周:体面的撤退

第四周:体面的撤退

迁移回TypeScript的决定做得很快。不是投降,是承认上下文变了。

保留的Rust代码只有性能关键路径——那个WebSocket模块,确实无可替代。其余全部重写。重写花了三天,而之前用Rust写同样功能花了三周。

速度回来了,但有些东西也永远改变了。我对TypeScript的undefined is not a function多了份敬畏,开始用更严格的lint规则。 borrow checker 教会我的思维模式,留在了代码审查的习惯里。

作者说得很克制:什么都没真正"失败"。

这事在开发者社区引发了不少共鸣。有人坚持Rust是唯一的正路,有人觉得这种折腾纯属浪费时间。更常见的反应是:终于有人诚实地说出了 trade-off(权衡)的存在。

技术选型很少是非黑即白。Rust在某些战场是无敌的——系统编程、高频交易、游戏引擎。但在需要快速验证、团队流动快、生态依赖重的场景,它的优势会变成枷锁。

我现在回头看那四周,不觉得是浪费。它像一次高强度的训练营,让我看清了自己的真实需求:不是最安全的代码,是在安全性和速度之间找到当下的平衡点。

你的项目现在卡在哪个维度——是 latency 不够低,还是 velocity 不够快?