跳转到内容

Rust 与 C++、Go、Python 对比

“我该学 Rust,还是学 Go,还是继续用 Python?”刚接触 Rust 的人最常问的就是这个问题。老实说,答案取决于你想做什么。这一页提到的每门语言都是好语言,都有数百万人在用,只是各自做了不同的取舍。

不妨把编程语言想象成交通工具。跑车、货车和自行车都“很好”,只是你不会骑自行车去搬家具。这一页会用大白话讲清楚这些取舍,帮你为自己的任务挑对工具。我们会尽量做到公平,包括坦白说出 Rust 的短板。

Rust 最主要的承诺是同时做到速度和安全:

  • 像 C 和 C++ 一样快。 Rust 编译成原生机器码,而且没有垃圾回收器(garbage collector),所以不会因为清理内存而让程序卡顿。
  • 不用垃圾回收器也能保证内存安全。 所有权和借用规则在编译时检查。一整类 bug(使用已释放的内存、线程之间的数据竞争)在程序运行之前就会被拒绝。
  • 开箱即用的优秀工具。 一个工具 Cargo 就能构建代码、下载库、运行测试、生成文档。格式化工具(rustfmt)和代码检查工具(clippy)都是官方出品。
  • 友好的编译器报错。 编译器经常会直接告诉你该怎么修复问题。

开发者们似乎也很喜欢它:在 2025 年 Stack Overflow 开发者调查(英文)中,Rust 再次被评为“最受推崇”(most admired)的编程语言,也就是说,大多数用过它的人都还想继续用。

先从一个小任务开始:把列表里的偶数加起来。下面是 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 循环)。像这样的小程序,区别主要在写法风格上。真正的差异要到大一些的程序里才会显现。

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 here
4 | v.push(4);
| ^^^^^^^^^ mutable borrow occurs here
5 | 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++,但把它们混在一起需要花些功夫。

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 := 0
for 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、泛型、生命周期、宏),能力更强,但也要花更长时间来学。

Python 和 Rust 差别很大,而且它们常常是搭配使用,而不是互相替代。

速度。 Python 是解释执行的,所以做大量计算的纯 Python 代码比编译型代码慢得多。这也是为什么流行的 Python 库常常在底层用 C、C++ 或 Rust 来干重活。

类型。 在 Python 里,类型是在程序运行时检查的。下面这个函数传数字能正常工作,传字符串就会出错,但你要等到运行那一行时才会发现:

def add_tax(price):
return price * 1.2
print(add_tax(10)) # 12.0
print(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(或 C++)是很好的选择。
  • 出 bug 的代价高吗? 安全敏感的代码、长时间运行的服务器,以及很多人依赖的代码,最能从 Rust 的编译时检查中受益。
  • 你要做一个想分享给别人的命令行工具吗? Rust 能生成一个快速的单一可执行文件,不需要额外安装运行时。Go 在这方面也很出色。
  • 你需要快速做出一个 Web 服务,而团队对这几门语言都不熟吗? Go 大概能让你更快上线。Rust 也完全能胜任(见项目:Web API),只是学习时间更长。
  • 只是一个快速脚本、数据分析或机器学习实验? 用 Python。等某个部分慢得受不了,再通过 PyO3 请出 Rust。
  • 已经有一个庞大的 C++ 代码库吗? 暂时继续用 C++,或者像 Android 那样,在新的、独立的模块里引入 Rust。

如果你只是想成为更好的程序员:学 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