Rust 与 C++、Go、Python 对比
“我该学 Rust,还是学 Go,还是继续用 Python?”刚接触 Rust 的人最常问的就是这个问题。老实说,答案取决于你想做什么。这一页提到的每门语言都是好语言,都有数百万人在用,只是各自做了不同的取舍。
不妨把编程语言想象成交通工具。跑车、货车和自行车都“很好”,只是你不会骑自行车去搬家具。这一页会用大白话讲清楚这些取舍,帮你为自己的任务挑对工具。我们会尽量做到公平,包括坦白说出 Rust 的短板。
Rust 擅长什么
Section titled “Rust 擅长什么”Rust 最主要的承诺是同时做到速度和安全:
- 像 C 和 C++ 一样快。 Rust 编译成原生机器码,而且没有垃圾回收器(garbage collector),所以不会因为清理内存而让程序卡顿。
- 不用垃圾回收器也能保证内存安全。 所有权和借用规则在编译时检查。一整类 bug(使用已释放的内存、线程之间的数据竞争)在程序运行之前就会被拒绝。
- 开箱即用的优秀工具。 一个工具 Cargo 就能构建代码、下载库、运行测试、生成文档。格式化工具(
rustfmt)和代码检查工具(clippy)都是官方出品。 - 友好的编译器报错。 编译器经常会直接告诉你该怎么修复问题。
开发者们似乎也很喜欢它:在 2025 年 Stack Overflow 开发者调查(英文)中,Rust 再次被评为“最受推崇”(most admired)的编程语言,也就是说,大多数用过它的人都还想继续用。
同一个任务,四种语言
Section titled “同一个任务,四种语言”先从一个小任务开始:把列表里的偶数加起来。下面是 Rust 版:
fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; let sum: i32 = numbers.iter().filter(|n| *n % 2 == 0).sum(); println!("偶数之和:{sum}");}输出:
偶数之和:12用 C++ 写同一个程序:
#include <iostream>#include <vector>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6}; int sum = 0; for (int n : numbers) { if (n % 2 == 0) { sum += n; } } std::cout << "偶数之和:" << sum << "\n";}用 Go:
package main
import "fmt"
func main() { numbers := []int{1, 2, 3, 4, 5, 6} sum := 0 for _, n := range numbers { if n%2 == 0 { sum += n } } fmt.Printf("偶数之和:%d\n", sum)}最后是 Python:
numbers = [1, 2, 3, 4, 5, 6]total = sum(n for n in numbers if n % 2 == 0)print(f"偶数之和:{total}")四个程序打印的是同一行。Python 最短,Go 和 C++ 用的是普通循环,Rust 用的是迭代器链加一个闭包(在 Rust 里你也可以写 for 循环)。像这样的小程序,区别主要在写法风格上。真正的差异要到大一些的程序里才会显现。
Rust 与 C++
Section titled “Rust 与 C++”C++ 和 Rust 瞄准的是同一个领域:需要完全掌控内存的高性能程序,比如浏览器、游戏引擎、数据库和操作系统。两者最大的区别在于:由谁来检查内存用得对不对。
在 C++ 里,检查的人是你。来看一个经典 bug。C++ 编译器会毫无怨言地接受下面的代码,但 push_back 可能会把 vector 搬到新的内存里,于是 first 可能指向一块已经被释放的内存:
std::vector<int> v = {1, 2, 3};int& first = v[0];v.push_back(4); // 可能会搬动 vector 的内存……std::cout << first << "\n"; // ……所以这里可能读到已释放的内存同样的错误在 Rust 里根本编译不过:
fn main() { let mut v = vec![1, 2, 3]; let first = &v[0]; v.push(4); println!("{first}");}error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable --> src/main.rs:4:5 |3 | let first = &v[0]; | - immutable borrow occurs here4 | v.push(4); | ^^^^^^^^^ mutable borrow occurs here5 | println!("{first}"); | ----- immutable borrow later used here编译器说的是:v 已经被不可变地借用了(first),所以不能再把它可变地借用给 push,因为后面还要用到 first。
这在实际中非常重要。Chromium 团队的报告显示,他们大约 70% 的严重安全 bug 都是内存安全问题(英文)。Google 的 Android 团队这几年一直用 Rust 编写新代码。他们在 2022 年报告说 Android 的 Rust 代码中没有发现任何内存安全漏洞(英文),2025 年又报告说,Rust 代码的内存安全漏洞密度比他们的 C 和 C++ 代码低 1000 多倍(英文)。Linux 内核(英文)也支持用 Rust 编写的代码。
工具链: C++ 有很多种构建系统和包管理器,团队往往要花不少时间在环境配置上。Rust 只有一个标准工具 Cargo,所以每个 Rust 项目的构建方式都一样。
学习曲线: 两门语言都不好学。C++ 非常庞大,很多规则是你在运行时犯了错才学会的。Rust 的规则很严格,但编译器会强制执行并解释这些规则,所以你在编译时就能学会它们。
C++ 仍然占优的地方: 几十年积累下来的现有代码、库和经验丰富的开发者。如果你的公司或者你用的游戏引擎是建立在 C++ 之上的,C++ 往往是更务实的选择。Rust 可以调用 C 代码,也能通过 C 风格的接口调用 C++,但把它们混在一起需要花些功夫。
Rust 与 Go
Section titled “Rust 与 Go”Go 和 Rust 经常被拿来比较,因为它们都是现代的编译型语言,都很适合写服务器和命令行工具。但它们的设计目标并不一样。
垃圾回收与所有权。 Go 使用垃圾回收器(英文),在程序运行时找出并释放不再使用的内存。这让 Go 代码写起来更简单:你永远不用考虑某个值归谁所有。代价是多占一些内存和 CPU,还有短暂的停顿。Rust 没有垃圾回收器。内存会在一个确定的时间点释放,也就是所有者离开作用域的时候。这样性能更可预测,但你必须学会所有权和借用。
并发。 Go 的 goroutine 和 channel 以简单好用出名。下面这个小例子并行计算三个数的平方,再把结果加起来:
results := make(chan int)
for n := 1; n <= 3; n++ { go func() { results <- n * n }()}
total := 0for i := 0; i < 3; i++ { total += <-results}fmt.Printf("总和:%d\n", total)Rust 版本用的是线程和信道(channel)。它稍微啰嗦一点:要为每个线程克隆一个发送端,还要用 move:
use std::sync::mpsc;use std::thread;
fn main() { let (tx, rx) = mpsc::channel();
for n in 1..=3 { let tx = tx.clone(); thread::spawn(move || { tx.send(n * n).unwrap(); }); } drop(tx); // 关闭我们自己的这份发送端,下面的循环才能结束
let total: i32 = rx.iter().sum(); println!("总和:{total}");}输出:
总和:14多敲这几个字换来的是:如果两个线程可能同时修改同一份数据(也就是数据竞争),Rust 会拒绝编译。在 Go 里,数据竞争是可能发生的;Go 提供了一个竞态检测器(英文),在程序运行时把它们找出来。更多内容请看 Rust 并发。
编译速度。 Go 从一开始就是为快速编译而设计的。它的 FAQ 里说,构建一个大型可执行文件最多只需要几秒钟(英文)。Rust 编译得更慢,因为编译器要做多得多的检查和优化。在大项目里你会明显感觉到这一点。
简洁性。 Go 刻意保持为一门小语言,要学的特性不多,所以很多人发现自己很快就能读懂 Go 代码。Rust 的特性更多(trait、泛型、生命周期、宏),能力更强,但也要花更长时间来学。
Rust 与 Python
Section titled “Rust 与 Python”Python 和 Rust 差别很大,而且它们常常是搭配使用,而不是互相替代。
速度。 Python 是解释执行的,所以做大量计算的纯 Python 代码比编译型代码慢得多。这也是为什么流行的 Python 库常常在底层用 C、C++ 或 Rust 来干重活。
类型。 在 Python 里,类型是在程序运行时检查的。下面这个函数传数字能正常工作,传字符串就会出错,但你要等到运行那一行时才会发现:
def add_tax(price): return price * 1.2
print(add_tax(10)) # 12.0print(add_tax("10")) # TypeError: can't multiply sequence by non-int of type 'float'Python 有可选的类型提示,但 Python 运行时并不会强制检查它们。在 Rust 里,所有类型都会在程序运行之前检查:
fn add_tax(price: f64) -> f64 { price * 1.2}
fn main() { println!("{}", add_tax(10.0)); println!("{}", add_tax("10"));}error[E0308]: mismatched types --> src/main.rs:7:28 |7 | println!("{}", add_tax("10")); | ------- ^^^^ expected `f64`, found `&str` | | | arguments to this function are incorrect这条报错的意思是“类型不匹配”:函数需要一个 f64,你却传了一个 &str。
Python 仍然更合适的场景: 快速脚本、数据分析、机器学习、notebook、自动化,还有教新手入门。Python 的数据科学生态非常庞大,几分钟就能把一个想法试出来。如果你的程序大部分时间都在等网络或数据库,Python 的速度往往无关紧要。
两者一起用: PyO3(英文)项目让你可以用 Rust 编写 Python 模块,这样你可以保留 Python 代码,只把慢的那部分换成 Rust。有些流行的 Python 工具本身就是用 Rust 写的;比如 Stack Overflow 的调查就提到,Python 包管理器 uv 是用 Rust 构建的(英文)。
下面列的是总体倾向,而不是硬性规则。用这些语言中的任何一门,只要写得好,都能“足够快”。
| Rust | C++ | Go | Python | |
|---|---|---|---|---|
| 速度 | 非常快,原生代码,无 GC | 非常快,原生代码,无 GC | 快,原生代码,带 GC | 纯 Python 做大量计算时较慢 |
| 内存安全 | 编译时检查(unsafe 之外) |
由程序员负责 | 有 GC;仍可能出现数据竞争 | 有 GC;安全,但类型错误要到运行时才出现 |
| 学习曲线 | 一开始很陡 | 很陡,而且语言非常庞大 | 平缓 | 最平缓 |
| 编译时间 | 偏慢 | 偏慢(取决于项目) | 非常快 | 无需编译 |
| 生态 | 较年轻,正在成长;内置 Cargo | 庞大成熟;构建工具很多 | 标准库强大,非常适合写服务器 | 极其庞大,尤其是数据和机器学习 |
| 典型用途 | 命令行工具、服务器、系统代码、WebAssembly、嵌入式 | 游戏、浏览器、高性能系统和遗留系统 | Web 服务、云和 DevOps 工具 | 脚本、数据科学、机器学习、自动化 |
什么时候该选 Rust?
Section titled “什么时候该选 Rust?”问问自己下面这些问题:
- 你需要极致的速度或很低的内存占用吗,比如游戏引擎、数据库或运行在小型设备上的代码?Rust(或 C++)是很好的选择。
- 出 bug 的代价高吗? 安全敏感的代码、长时间运行的服务器,以及很多人依赖的代码,最能从 Rust 的编译时检查中受益。
- 你要做一个想分享给别人的命令行工具吗? Rust 能生成一个快速的单一可执行文件,不需要额外安装运行时。Go 在这方面也很出色。
- 你需要快速做出一个 Web 服务,而团队对这几门语言都不熟吗? Go 大概能让你更快上线。Rust 也完全能胜任(见项目:Web API),只是学习时间更长。
- 只是一个快速脚本、数据分析或机器学习实验? 用 Python。等某个部分慢得受不了,再通过 PyO3 请出 Rust。
- 已经有一个庞大的 C++ 代码库吗? 暂时继续用 C++,或者像 Android 那样,在新的、独立的模块里引入 Rust。
如果你只是想成为更好的程序员:学 Rust 会让你真正理解内存是怎么工作的,这些知识在任何语言里都用得上。
Rust 的真实缺点
Section titled “Rust 的真实缺点”Rust 并不完美。下面是大家最头疼的几件事:
- 学习曲线是真实存在的。 刚开始和借用检查器打交道的那几周可能会很受挫,准备好“和编译器较劲”一阵子吧。一旦理解了所有权,事情就会轻松很多。
- 编译时间比 Go 慢,大项目和 release 构建尤其明显。
- 有些东西更难表达。 对象之间有大量相互链接的图状数据,或者大量共享可变状态的代码,需要用到智能指针之类的工具,也需要更多的前期规划。
- 生态还比较年轻。 在某些领域(GUI 应用、部分科学计算库),成熟的选择比 C++ 或 Python 少。
- 用的人(目前)还比较少。 在 2025 年 Stack Overflow 调查(英文)中,说自己用 Python(约 58%)或 C++(约 24%)的受访者远多于用 Rust(约 15%)的。这意味着能招到、能请教、能在工作中向他学习的资深 Rust 开发者更少。
- 简单的事也要写更多代码。 就像信道那个例子展示的,别的语言很随意的地方,Rust 常常要求你把话说清楚。
- Rust 拥有 C++ 级别的速度,内存安全在编译时检查,还有出色的内置工具。
- 和 C++ 相比,Rust 能在程序运行前就防止一整类内存 bug;C++ 的现有代码和库则多得多。
- 和 Go 相比,Rust 没有垃圾回收器,并能在编译时阻止数据竞争;Go 更简单,编译也快得多。
- 和 Python 相比,Rust 快得多,而且在运行前检查类型;Python 写起来更快,在数据科学领域占主导地位。PyO3 能让两者结合起来。
- Rust 的主要代价是陡峭的学习曲线、较慢的编译速度和较年轻的生态。
小测验
1. Rust 不用垃圾回收器,是怎样管理内存的?
2. 下面哪一项是 Go 相对 Rust 的合理优势?
3. 你有一个 Python 程序,其中一个函数慢得离谱。常见的做法是什么?
4. 在 C++ 与 Rust 的例子中,先保存 &v[0] 再往 v 里 push 的代码会怎样?
得分: 0 / 4
- 《Rust 程序设计语言》简体中文版:介绍:官方教程用自己的话讲 Rust 适合哪些人。
- Rust in Android: move fast and fix things(Google 安全博客)(英文):一个大型团队在 C 和 C++ 旁边使用 Rust 的真实数据。
- Stack Overflow Developer Survey 2025:Admired and Desired(英文):开发者如何看待 Rust、Go、Python、C++ 等语言。
- Go FAQ:Why did you create a new language?(英文):Go 自己的设计目标,有助于理解它的强项在哪里。
- PyO3 用户指南(英文):如何用 Rust 编写 Python 扩展。