观前声明:
如果你非常喜欢Rust,或是他的粉丝。
请不要浪费时间立刻退出这篇文章,这对你我都好。
谢谢合作。
我不是没写过 Rust 的新手。
相反,正是因为我用它写了相当长时间的业务代码,
经历过从入门到“上手”再到“厌倦”**的全过程,我才决定写下这篇文章。
Rust 的确是一门在设计上极其优秀的语言,它的内存安全模型和类型系统绝对是计算机历史上科学的瑰宝。
但我从一位企业CTO角度出发:在实际的软件工程世界里,优秀的理论设计并不等同于优秀的产品 。
我用 Rust 写核心业务代码快两年了。从最初被所有权(Ownership)机制惊艳,到中间与借用检查器(Borrow Checker)的搏斗,再到如今的生理性厌恶。
我现在最大的感受只有一句话:Rust 是一门理论上完美的语言,但被一个草台班子社区,做成了一个极其难用、且充满政治恶臭的工业产品。
如果你在犹豫要不要在公司的 Web 后端引入 Rust,请看完这篇包含 Node.js、Go 和 Rust 的残酷对比指南。
这也是我逐渐远离 Rust,甚至对其产生反感的原因。以下是我的几点核心劝退理由:
一、生态现状:114514 种造轮子的姿势
Rust 社区最让我感到窒息的,是一种“碎片化 ”的繁荣假象。
如果你习惯了Node.Js/Go/Java 那种“大厂背书、官方统一”的生态,来到 Rust 会感到极度的水土不服。Rust 官方的标准库(std)奉行极简主义,这本没问题,但问题在于社区并没有形成合力,而是陷入了某种“自我感动式的重复造轮子”。
Rust 的设计哲学是“小核心”,标准库寒酸得令人发指。这导致了严重的生态碎片化。
-
Node.js:虽然
node_modules重,但核心 API(fs,http,net)高度统一。想读文件?fs.readFile。想起服务?http.createServer。甚至不用动脑子。 -
Go:大厂背书,标准库极其丰富。
net/http是工业级的,database/sql是标准化的。社区库如GORM极其成熟。 -
Rust:草台班子大本营。
- 文件系统?你得在
std::fs,tokio::fs,async_std::fs里选妃,互不兼容。 - 数据处理?为了证明“Rust 比 Python 快”,社区写了 1919 个简陋版 Pandas,每个都只有 10% 的功能,作者写了一半就弃坑去写下一个“更 Rust 风味”的轮子了。
- 文件系统?你得在
二、实战代码对比:谁在干活,谁在自虐?
让我们来看一个最简单的后端场景:“从数据库查个用户,返回 JSON”。
1. Node.js (JavaScript/TypeScript)
体验: 丝滑,无脑,快。
Node 的单线程 Event Loop 天生适合高并发 IO,你根本不需要关心什么线程安全、锁、内存分配。
// Node.js: 甚至初次接触编程第一天都能写出来
// 甚至不需要定义结构体,直接拿 JSON
app.get('/user/:id', async (req, res) => {
try {
// DB 驱动自动处理连接池,甚至不需要你关心它是不是全局变量
const user = await db.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
res.json(user);
} catch (e) {
res.status(500).send(e.message);
}
});
2. Go (Golang)
体验: 稳重,枯燥,但极其高效。
虽然 if err != nil 很烦,但除此之外没有心智负担。结构体定义清晰,GC 帮你兜底。
// Go: 简单粗暴
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func GetUser(c *gin.Context) {
var user User
id := c.Param("id")
// GORM 或 sqlx 极其成熟,连接池并发安全是标配
if err := db.Get(&user, "SELECT * FROM users WHERE id = $1", id); err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
}
// 如果你使用orm库事情会变得更简单
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// 1. 定义模型
// 我们就用GORM做例子(他甚至不算是一个简洁优雅的轮子,只是使用维护积极使用人数多)
// 他会自动处理结构体到数据库表的映射,甚至自动维护 ID, CreatedAt, UpdatedAt
type User struct {
gorm.Model // 自动包含 ID, CreatedAt, UpdatedAt, DeletedAt
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
// 初始化 DB(连接池由 GORM 自动管理,并发安全)
dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable"
db, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
// 甚至可以自动建表/迁移(Rust里得写 migration 脚本)
db.AutoMigrate(&User{})
r := gin.Default()
// 2. 业务逻辑
r.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
var user User
// 核心代码就这一行!
// 不需要写 "SELECT * FROM...", 不需要 RowMapper
// GORM 自动解析 ID,自动把结果填充到 user 结构体
result := db.First(&user, id)
if result.Error != nil {
c.JSON(404, gin.H{"error": "User not found"})
return
}
// 直接返回 JSON
c.JSON(200, user)
})
r.Run()
}
3. Rust (Web 后端现状)
体验: 坐牢。
为了实现上面两行代码的功能,你得引入 Tokio (运行时), Serde (序列化), sqlx (数据库), Axum (Web框架)。然后开始和编译器搏斗。
我真的很难说这种代码是具有良好可读性的,这就是你们追求的rust风味吗?:)
// Rust: 为了“安全”而牺牲一切开发效率
// 首先,你得把连接池包成线程安全的
struct AppState {
// 为什么要 Arc?因为多线程。为什么要 Clone?因为所有权。
db: Arc<Pool<Postgres>>,
}
async fn get_user(
// 看着这堆 Extractor,还得理解 State 的提取原理
State(state): State<Arc<AppState>>,
Path(id): Path<i32>
) -> Result<Json<User>, StatusCode> {
// 充满了 Result 处理,unwrap, map_err...
// 这里如果不小心,或者为了省事,很多新手会写一堆 .clone()
let row = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
.fetch_one(&*state.db)
.await
.map_err(|e| {
// 错误处理极其繁琐
eprintln!("DB error: {}", e);
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(row))
}
后果是什么?
Node.js 虽然单线程 CPU 弱,但 IO 极强还有多进程IPC通信死扛。
Go 有 GC 稍微占点内存,但吞吐量极其稳定。
而 Rust 新手写出来的代码,为了绕过借用检查,满屏的 .clone() 深拷贝。
结果就是:一群糟糕的程序员用着最底层的语言,写出了比 Python 还没效率的代码,不仅开发慢,上线后 CPU 还狂飙,甚至因为大文件没切片这种问题导致物理 OOM(没有 GC 帮你回收垃圾,你没释放就是真泄露)。
三、令人窒息的社区:极端政治化与“饭圈”恶臭
如果说技术难点我还能克服,那么 Rust 社区的氛围就是让我彻底退坑的理由。
这个社区现在的氛围非常诡异,充斥着一种宗教般的狂热和极端的身份政治(Identity Politics)。
1. 极端群体与政治正确(Political Correctness)的绑架
首先再次叠甲,我不歧视任何群体,但在 Rust 社区,技术似乎已经不是第一位了,屁股坐在哪里才是。
- 现在的 Rust 官方社区过度关注 Code of Conduct(行为准则),甚至成为了某些极端 LGBTQ+ (某蓝白旗 🍥)群体的自留地。
- 在 GitHub Issue 或 Discord/QQ社群里,如果你用错了一个代词(Pronoun),或者你的观点不够“进步”,你会被光速打上“不包容”的标签,甚至被一群人包括不限于问候祖宗十八代的人身攻击、踢出维护者名单或是社群。
- 我们是工程师,我们来这里是为了讨论数据结构模型、讨论软件架构的,不是来参加社会运动的。
- 当一群人花在审查社区言论上的时间多于优化代码的时间,这个项目就已经变质了。
2. RIIR (Rewrite It In Rust) 警察
这帮人就像是一群传教士。无论你讨论什么项目,总有人跳出来复读:“为什么不用 Rust 重写?Rust 安全。”
他们把使用 Rust 上升到了道德高度。
- 用 C++?你是不负责任,制造内存漏洞。
- 用 Node.js?你是制造电子垃圾。
- 用 Go?你有 GC,你不仅慢,你还没有泛型品味(虽然现在有了)。
拜托,Node.js 支撑了全球 80% 的 Web 流量,Go 支撑了整个云原生(Kubernetes, Docker),你们 Rust 除了重写了一堆半成品 ls 和 cat 命令,在业务层还有什么拿得出手的统治级产品吗?
四、写给理性的开发者:如何选择?
回到现实的业务场景,请保持清醒:
当你冷静下来思考,大部分业务真的需要 Rust 吗?
- 我们需要的是快速迭代,Rust 的编译速度和心智负担并不允许。
- 我们需要的是生态成熟,是开箱即用的 ORM、RPC 和监控体系,而不是去 Github 上找一个两年前更新的
0.3版本库自己魔改。 - 我们需要的是招人容易,而不是花高薪招一个只会写
unwrap()的 Rust 新手(参考前段时间cloudflare爆炸事件)。 - (18 封私信 / 50 条消息) 一次 unwrap() 引发的全球宕机:Cloudflare 故障报告背后的 Rust 安全反思 - 知乎
-
Web 后端、微服务、CRUD 业务:
- 首选 Go:如果你追求性能和开发效率的平衡。没有心智负担,大厂轮子多,招人容易。
- 次选 Node.js:如果你团队全栈,或者要做快速原型。生态无敌,开发速度极快。
- 甚至 Java:Spring 虽然重,但它稳,生态是航空母舰级别的。
-
什么时候用 Rust?
- 你在写数据库内核。
- 你在写操作系统、浏览器引擎、WebAssembly。
- 你在做某某国家机密任务。
- 你需要写某某超低延迟金融量化系统。
总结:
不要为了所谓的“极客感”去受这份罪。
Rust 是一把精密的手术刀,但现在的社区正试图用它来切西瓜,还指责拿西瓜刀的人“不政治正确”。
这种草台班子社区维护的草台班子产品,谁爱用谁用,我不伺候了。
—— 一个只想搞定业务、拒绝被“信仰”绑架的架构师