别把 Rust 捧上天了:我为什么不喜欢RUST语言及他的社区

观前声明: 如果你非常喜欢Rust,或是他的粉丝。 请不要浪费时间立刻退出这篇文章,这对你我都好。 谢谢合作。 我不是没写过 Rust 的新手。 相反,正是因为我用它写了相当长时间的业务代码, 经历过从入门到“上手”再到“厌倦”**的全过程,我才决定写下这篇文章。 Rust 的确是一门在设计上极其优

观前声明:

如果你非常喜欢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 除了重写了一堆半成品 lscat 命令,在业务层还有什么拿得出手的统治级产品吗?

四、写给理性的开发者:如何选择?

回到现实的业务场景,请保持清醒:

当你冷静下来思考,大部分业务真的需要 Rust 吗?

  1. Web 后端、微服务、CRUD 业务

    • 首选 Go:如果你追求性能和开发效率的平衡。没有心智负担,大厂轮子多,招人容易。
    • 次选 Node.js:如果你团队全栈,或者要做快速原型。生态无敌,开发速度极快。
    • 甚至 Java:Spring 虽然重,但它稳,生态是航空母舰级别的。
  2. 什么时候用 Rust?

    • 你在写数据库内核。
    • 你在写操作系统、浏览器引擎、WebAssembly。
    • 你在做某某国家机密任务。
    • 你需要写某某超低延迟金融量化系统。

总结:
不要为了所谓的“极客感”去受这份罪。
Rust 是一把精密的手术刀,但现在的社区正试图用它来切西瓜,还指责拿西瓜刀的人“不政治正确”。
这种草台班子社区维护的草台班子产品,谁爱用谁用,我不伺候了。

—— 一个只想搞定业务、拒绝被“信仰”绑架的架构师


LICENSED UNDER CC BY-NC-SA 4.0
评论