从C++指针地狱到Rust枚举天堂性能翻三倍


我用三种方式写了个软件,结果Rust一句话让我顿悟:我之前二十年,白干了!
作者:杰弗里·伦尼(Jeffrey Rennie)  (一个搞PDF文档的程序员大叔,头发可能不多,但脑子贼灵)


大家好,我是个专门“折腾PDF”的程序员。你别看PDF现在人人会用,点一下“打印为PDF”就完事了,但背后可复杂了,复杂到什么程度?——它的说明书有756页!比你语文课本还厚!里面还得懂图片压缩、字体解码、各种加密……简直像在拆一颗定时炸弹。

但今天咱不讲炸弹,讲一个程序员的“顿悟时刻”。



我用三种语言,写了三遍同样的软件

过去20年,我为了处理PDF,可没少折腾。我试过:

1. Python:用个叫PLY的工具,像个刚学编程的小白,一步一步解析。
2. C++:用更高级的工具Flex和Bison,像个中学生,拿着计算器算语法。
3. C++(再战):自己手写“递归下降解析器”,像个学霸,非要手算微积分。

最后,我决定试试Rust——一个号称“内存安全、性能炸裂”的新语言。

我心想:不就是写个PDF处理工具嘛,照着C++的路子抄一遍,岂不美滋滋?

结果……Rust编译器直接给我一巴掌:“你这代码,不行!”



Rust:你这代码,我编译不了!

我照着C++的老套路,在Rust里搞了个“对象树”,每个对象都用指针连来连去,像蜘蛛网一样。

结果Rust编译器疯狂报错:

> ❌ “这个指针的生命周期是啥?”  
> ❌ “你这里又改又读,想干啥?!”  
> ❌ “你这内存管理,迟早出事!”

我整整折腾了一周,想尽办法“说服”Rust编译器放我一马。结果它油盐不进,死活不让我编译通过。

我崩溃了,仰天长叹:“Rust啊Rust,你是不是在针对我?”

最后,我认输了,决定换个思路:既然你Rust不让这么写,那我就按你的规矩来!



灵光一闪:用“枚举”代替“指针链”

我放弃了C++那种“万物皆对象、指针乱飞”的老思路,改用Rust的枚举(enum) 来表示PDF里的各种数据。

你可能不知道“枚举”是啥,我打个比方:

- C++的做法:  
  把“名字”“生日”“爸爸”“妈妈”都做成独立的小纸条,然后用回形针(指针)连起来。  
  想删一个人?好,你得一张张撕纸条,一个个拆回形针,累死你。

- Rust的新思路:  
  直接拿一个大信封,把所有信息全塞进去。  
  想删?直接把信封扔垃圾桶,完事!

而且,Rust还教我一个小技巧:短字符串直接写在信封上,不用贴纸条!  
比如“name”“birthday”这种短词,根本不用申请内存,省时省力!



结果:性能直接起飞!

我一测性能,好家伙——Rust版本比C++快了整整3倍!

不是因为Rust语言本身多牛,而是Rust逼我用了更聪明的内存结构

你猜怎么着?如果我当年用C++也这么写,C++可能还更快!但问题是——我根本没想到还能这么写啊!



来算笔账:删一个对象,要多少操作?

假设我们要删掉这个“Michael Doe”的信息:

json
{
  "name": "Michael Doe",
  "birthday": [1995, 3, 10],
  "father": R-0,
  "mother": R-1
}

- C++ 老方法:  
  - 释放8个对象(数字、链接、数组、字符串……)  
  - 减13次引用计数(每次减都要判断要不要删)  
  - 总共15次释放 + 13次判断,像在玩扫雷,步步惊心。

- Rust 新方法:  
  - 释放1个数组、1个哈希表、1个长字符串  
  - 其他短字符串根本没分配内存!  
  - 总共3次释放,0次判断,干净利落,像一键清空回收站!



所以,Rust真的比C++快吗?

不一定。

但如果让你用“最自然、最顺手”的方式写代码,Rust会自动把你往高性能的路子上推

而C++呢?它像一辆跑车,性能猛,但你要是开得不好,分分钟撞墙。

Rust呢?它像一辆智能电动车,方向盘会自动纠正你的错误,还顺便带你抄近道



最后,作者的灵魂发问:

1. C++程序员们,你们现在还用2005年的老套路吗?  
   当年没有std::variant,没有“小字符串优化”,现在有了,你们改了吗?

2. 你最喜欢的编程语言,有Rust这种“枚举大法”吗?  
   能不能也写出这么快、这么安全的代码?



总结金句:

> Rust不是更快,而是它不让你写慢代码。  
> 它像一个严格的数学老师,不让你跳步骤,结果你一算,嘿,反而算得更快了!

所以,有时候——不是你不够聪明,而是你用的工具,没逼你变聪明。



(完)

P.S. 如果你现在还在用C++写指针满天飞的代码,小心Rust哪天找你“谈心”哦~