【Rust日报】2026-10-19 借用检查可以倒着做

💡 原文中文,约3600字,阅读约需9分钟。
📝

内容提要

本期Rust社区汇总包含四项内容:Valen编译器提出反向借用检查,从函数末尾向前扫描,通过pending列表在USE、MUTATE、DECLARE处判断引用是否失效,作者称可减少查找,但未做速度基准测试;有文章用穷举搜索为FPU模拟器找到含5次运算的浮点公式,未找到4次运算版本;职业建议帖指出不应绑定单一语言,纯Rust岗位较少,常需C++或Python配合;最后介绍一个六状态SQL tokenizer,仅将字面量替换为?以生成查询模板,不构建语法树。

🔎

延伸解读

反向借用检查的潜在优势与未验证的性能

Valen 编译器将内存安全检查改为从函数末尾向前扫描,作者认为这能减少一次查找、在循环中更易判断引用是否被重新赋值,并让每个节点在分组和检查阶段各处理一次。但文章明确表示速度优势尚未经过基准测试,因此这些理由目前只是设计上的推测,实际性能提升仍需验证。

穷举搜索的局限:未找到更短公式

作者用穷举搜索寻找不超过 5 次运算的公式,找到了若干 5 运算版本,但没有找到 4 运算公式。搜索将重复子表达式算作多次运算,且测试用例仅 20 个,因此结果不能证明 4 运算公式不存在。手工优化后的公式对 2 的幂会翻转符号位,说明搜索得到的公式仍需人工检查边界情况。

Rust 求职的现实:纯 Rust 岗位有限

评论普遍认为纯 Rust 岗位较少,更常见的是 Rust 与 C++ 或 Python 配合的职位。有评论建议先学 C++,因为 C++ 有助于理解 Rust 且需求更大;也有评论提到航空航天、机器人等领域纯 Rust 职位在变多,以及 Python 岗位中用 Rust 做优化的机会增加。这些观点来自个人经验,并非系统调查。

轻量 SQL tokenizer 的取舍:简单但功能有限

作者为满足 GDPR 要求,只替换 SQL 字面量而不构建语法树,用六状态状态机处理字符串、数字、双引号、反引号和美元引号。这种方法能生成查询模板并提取参数,用于识别 N+1 查询,但作者明确它不识别列和 join,也不建语法树,因此不适合需要理解查询结构的复杂分析场景。

❓

Q&A

Valen 编译器的反向借用检查是怎么工作的?

Valen 的安全检查从函数最后一条语句向前扫描到开头,维护一个 pending 列表:遇到 USE 把变量放入 pending,遇到 MUTATE 检查 pending 中是否有被这次修改失效的变量,遇到 DECLARE 把变量从 pending 中移除。这样能发现引用在失效后是否还被使用。

反向借用检查相比 rustc 的借用检查有什么不同?

rustc 的 NLL 和 Polonius 先做 region 约束求解,再向前检查冲突;rustc 会向后扫描确定变量使用位置,但内存安全检查仍向前走。Valen 则把内存安全检查本身做成反向扫描,从函数末尾向前进行。

反向借用检查有什么好处?作者做基准测试了吗?

作者给出三条理由:少一次先记下最后使用位置再跳回去的查找;循环里更容易判断引用有没有被重新赋值;每个节点在分组阶段和检查阶段各处理一次。但作者明确表示速度这一点还没有做过基准测试。

穷举搜索为 FPU 模拟器找到了什么样的浮点公式?

搜索目标是给定 f32 返回只保留最低置位的浮点数。作者用穷举搜索找到了若干不超过 5 次运算的公式,但没有找到 4 次运算的版本。其中一个 5 运算公式可以复用一次 x.to_bits() & !f32::MANTISSA_MASK 来简化,不过该公式对 2 的幂会翻转符号位。

对于想用 Rust 找工作的人,社区有什么建议?

评论建议不要把职业绑在一种语言上,要做能换工具的工程师。纯 Rust 岗位较少,更常见的是同时要求 C++ 和 Rust,也有 Rust 加 Python(PyO3)的工作。有人建议先学 C++,因为有助于理解 Rust 且需求更大;也有观点认为航空航天、机器人、防务等领域的纯 Rust 职位在变多。

为什么作者要自己写一个 SQL 字面量替换器而不是用 sqlparser?

作者的目标是从生产 SaaS 的 trace 里分析 N+1 和重复查询,需要把字面量替换成 ? 以生成查询模板,同时字面量不进入报告以满足 GDPR。作者希望二进制小于 10 MB,只替换字面量,而 sqlparser 会构建语法树,不符合需求。

这个 SQL tokenizer 是如何实现的?支持哪些状态?

实现是一个六状态状态机,状态包括 Normal、InString、InNumber、InDoubleQuote、InBacktick、InDollarQuote。双引号和反引号标识符原样保留,美元引号覆盖 PostgreSQL 的 $$ 和 $tag$。主循环按当前状态调用对应函数,对字节走一遍。它不识别列和 join,也不建语法树。

🏷️

标签

➡️

继续阅读