首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Rust RFC 3593 深度解读:2024 Edition 保留的 `“...“` 无前缀受保护字符串字面量语法
📅 2026/10/16 2:25:00
✍️ 爱科研究院
👁 阅读 3,247
文档【免费下载链接】rfcsRFCs for changes to Rust项目地址https://gitcode.com/gh_mirrors/rf/rfcs点击查看免费下载导读本文围绕 RFC 3593Feature Nameunprefixed_guarded_strings展开讲解 Rust 语言如何在 2024 Edition 中提前保留#foo#这类无前缀受保护字符串字面量unprefixed guarded string literal的语法空间为未来可能新增的字符串字面量形式预留兼容性通道。读完本文你将理解 Rust 的语法保留syntactic reservation机制、Edition 边界在宏兼容性中的作用、哪些宏调用会因此从合法变为非法、如何通过插入空白符完成迁移以及该提案与 RFC 3101保留前缀、RFC 3475统一字符串字面量等提案之间的关系。一、提案概览从 2024 Edition 开始保留#foo#RFC 3593 的 Summary 非常简短却直击要害Beginning with the 2024 edition, reserve the syntax#foo#, as a way of future-proofing against future language changes.也就是说从 2024 Edition 开始#foo#这种语法形式将被编译器保留reserve它不携带任何语义仅仅是占用这块语法空间防止未来语言演进时破坏已有代码。这种先圈地、后使用的做法是 Rust 语言演进中常见的兼容性策略。为了理解它需要先厘清 Rust 中几类字符串字面量的形态。RFC 3593 用一段示例代码做了精确区分// Basic string literal普通字符串字面量 bar; // Prefixed string literal带前缀的字符串字面量 rfoo; // Prefixed guarded string literal带前缀的受保护字符串字面量 r#foo#; // Unprefixed guarded string literal无前缀的受保护字符串字面量 #foo#; // not yet reserved这里的关键词是guarded受保护r#foo#中#充当了原始字符串raw string的守卫符可以重复出现如r##...##用于在字符串内部安全地包含#之类的序列。而#foo#这种不带任何字母前缀的守卫式写法此前既没有语义、也未被保留正是 RFC 3593 要填补的缺口。本 RFC 的基本信息如下提案名称unprefixed_guarded_strings起始日期2024-03-24仓库中的提案原文text/3593-unprefixed-guarded-strings.md二、动机前缀保留了边缘情况却漏掉了RFC 3593 的动机部分明确指向前作 RFC 3101: Reserved prefixes in the 2021 edition。RFC 3101 在 2021 Edition 中保留了所有以标识符开头的字符串形式例如identfoo、ident##foo##。这些形式虽然与基础 Rust 语法不冲突但保留它们是为了避免未来宏macro的破坏性变更——这正是语法保留存在的意义。然而RFC 3101 的保留范围覆盖了带标识符前缀的字符串却没有覆盖无前缀的受保护字符串。RFC 3593 指出Reserving all identifier prefixes covers a large swath of future possibilities, but one edge case was not included: unprefixed guarded string literals.也就是说所有前缀字符串的组合都被圈住了唯独#...#这种以#开头、紧跟字符串字面量的形式成了漏网之鱼。与 RFC 3475 的关系动机部分还交代了与 RFC 3475: Unified String Literals统一字符串字面量提案的联动。RFC 3475 提议把#...#用作一种新类型字符串字面量的语法并希望在 2024 Edition 中保留该语法。但 RFC 3593 的作者判断RFC 3475 很可能赶不上 2024 Edition 的时间窗口它有可能被否决从而把这块语法留给完全不同的提案。因此RFC 3593 选择独立地、提前地在 2024 Edition 中保留#foo#语法。这样做的好处是未来无论哪个提案最终使用这块语法都不必再等下一个 Edition 边界下一届 Edition 大约要再等三年可以直接在此基础上推进。这与 RFC 3501 所确立的三年一届 Edition节奏密切相关。三、为什么必须跨 Edition 边界宏的 tokenize 兼容性RFC 3593 反复强调一个核心观点这种保留对普通终端用户几乎不可见唯一受影响的场景是宏调用。原因在于#foo#在基础 Rust 语法中本就没有意义普通代码根本写不出这种形式但宏尤其是macro_rules!接收的是 token 流#与字符串字面量如何被切分成 token会直接影响宏的匹配结果。RFC 3593 给出了一个极具说明力的示例macro_rules! demo { ( $a:tt ) { println!(one token) }; ( $a:tt $b:tt $c:tt ) { println!(three tokens) }; } demo!(foo); demo!(r#foo#); demo!(#foo#);在 2024 Edition 之前这段代码的输出为one token one token three tokens逐一分析demo!(foo)foo是一个完整 token字符串字面量匹配单 token 分支输出one tokendemo!(r#foo#)r#foo#是完整的原始字符串字面量 token同样匹配单 token 分支输出one tokendemo!(#foo#)在旧版分词规则下#被切成一个独立的 tokenfoo是另一个 token#收尾是第三个 token于是匹配三 token 分支输出three tokens。问题在于一旦未来某天 Rust 决定赋予#foo#真正的语义例如 RFC 3475 那样的新字符串字面量它就会像r#foo#一样被整体切分成一个 token导致上面第三个宏调用的行为从三个 token悄然变成一个 token。对于依赖 token 数量匹配的宏来说这就是静默的破坏性变更。因此必须在语法被赋予语义之前、跨越 Edition 边界完成保留让这类代码在进入新 Edition 时直接报错而非行为漂移。需要特别说明RFC 3593 原文在演示输出之后写的是Following the 2021 edition,#foo#would become a compiler error这里的2021应视为笔误——提案的 Summary 与本仓库标题都明确是2024 Edition即从 2024 Edition 起#foo#将产生编译错误。四、宏作者的实战指南合法与非法调用清单RFC 3593 的 Guide-level explanation 面向的是通过宏设计 DSL领域专用语言、以 token 树为输入的开发者。它给出的核心告诫是在设计 DSL 时要注意某些在 Rust 中没有意义的语法产生式依然被语法禁止——它们代表着未来语言发展的保留空间。在 2021 Edition 已保留的identifier#identifier、identifierstring contents、identifierchar contents、identifier#numeric literal之外从 2024 Edition 起#string contents允许任意数量的前置#也被保留。合法的宏调用RFC 3593 明确列出以下宏调用是合法的foo!(qux) foo!(qux#) foo!(r#qux#) foo!(# qux)注意最后一行foo!(# qux)#与字符串之间有空格此时#和qux是彼此独立的两个 token宏可以分别消费它们。这正是空白符即逃生通道的体现——该保留语法对空白敏感whitespace-sensitive#两侧只要任意一侧出现空白代码就能正常编译。非法的宏调用以下宏调用从 2024 Edition 起将非法产生分词错误foo!(#qux) foo!(#qux#) foo!(####qux####)三者的共同点是#与字符串字面量之间没有空白且#出现在字符串的紧邻左侧构成了被保留的#...形式。其中第三个例子说明无论多少个前置#都在保留之列对应分词规则里的#。迁移路径插入空白即可对于任何受影响的代码修复方式异常简单——在#与字符串之间插入空白// 迁移前2024 Edition 起报错 foo!(#qux#); // 迁移后等价且合法 foo!(# qux #); foo!(# qux#);这种机械式替换完全可以通过 rustfix 自动化完成RFC 3593 也明确提到了这一点。这与 Rust Edition 迁移的整体工具链思路一脉相承先让代码在旧、新两个 Edition 下都能编译交集阶段再完成最终切换。五、参考级说明新的分词规则与错误信息模板RFC 3593 的 Reference-level explanation 给出了正式的语法级定义新增的分词tokenizing规则如下RESERVED_GUARDED_STRING_LITERAL:# STRING_LITERAL含义是一个或多个#后紧跟着一个字符串字面量STRING_LITERAL即构成保留的受保护字符串字面量。判定 Edition 的方式与 Rust 既有机制一致以当前 crate 声明的 edition 为准即Cargo.toml中的edition字段。当 crate 以 2024 Edition 编译时任何命中上述规则的代码都会产生分词错误tokenization error。RFC 还建议实现一个 Edition 迁移工具在宏调用中查找#string#等模式并插入空白以强制正确分词。同时给出了建议的错误信息模板便于读者理解用户将看到的编译器输出error: invalid string literal -- file.rs:x:y | 1 | foo!(#qux#); | ^^^^^^^ help: try using whitespace here: # qux # | note: unprefixed guarded string literals are reserved for future use模板中包含了三个关键要素错误定位行列号、可直接执行的修复建议插入空白后的写法、以及根因说明无前缀受保护字符串字面量被保留以供未来使用。六、与 Edition 迁移体系的衔接cargo fix 与 rustfixRFC 3593 之所以能保持极低的影响面是因为它完全复用了 Rust 既有的 Edition 迁移机制。RFC 3085 定义了标准迁移流程准备升级运行cargo fix --edition自动应用迁移 lintmigration lint的补丁建议切换版本修改Cargo.toml的edition 2024清理收尾再次运行cargo fix应用仅在新 Edition 下可行的剩余修改手工处理手动解决剩余 lint 或错误。迁移 lint 的机制是每个 lint 对在新 Edition 下会出问题的代码发出警告并附带可应用的 diffsuggestion。对于 RFC 3593 的场景迁移工具只需在宏调用中发现#...#并插入空白即可让代码同时在 2015/2018/2021 与 2024 Edition 下编译通过属于典型的机械可应用machine applicable补丁。需要说明的是rustfix 工具本身无法做到百分百完美受条件编译、代码生成等因素影响因此 RFC 3085 也强调只要受影响的模式在真实代码中不常见自动化补丁覆盖不了边缘情况是可以接受的。由于这种保留在 2024 Edition 之前对普通代码完全不可见绝大多数 crate 在升级 Edition 时甚至不会触发任何相关警告只有那些在宏调用里写了紧凑#...#的代码才会被迁移工具介入。七、权衡与替代方案Drawbacks分词规则复杂化RFC 3593 承认的唯一缺点非常坦率让宏的分词规则变得更复杂。每增加一种保留形式编译器词法分析器lexer就需要多识别一种需要报错的模式。这是为未来兼容性付出的必然成本与 RFC 3101 的取舍完全一致。替代方案直接合并 RFC 3475RFC 3593 列出的替代方案只有一个直接合并 RFC 3475: Unified String LiteralsC 字符串字面量c...利用 RFC 3101 预留空间的路径如出一辙——2021 Edition 先圈住了identfoo空间2022 年的 RFC 3348 才用c…把这个空间兑现为具体特性。八、先例与生态参照RFC 3593 在 Prior art 一节引用了两条先例RFC 3101: Reserved prefixes in the 2021 edition本提案的直接前作。RFC 3101 在 2021 Edition 中系统性地保留了七类形式包括RESERVED_IDENTIFIER、RESERVED_BYTE_LITERAL、RESERVED_CHAR_LITERAL、RESERVED_RAW_BYTE_STRING_LITERAL、RESERVED_BYTE_STRING_LITERAL、RESERVED_RAW_STRING_LITERAL、RESERVED_STRING_LITERAL、RESERVED_NUMERIC_LITERAL为后续c...、r#原始标识符RFC 2151等特性的演进铺平了道路。RFC 3593 正是在这张保留清单上补上了无前缀守卫式这一角。Swift 的扩展字符串定界符Extended String DelimitersSwift 语言提供了#...#、##...##这样的扩展定界符语法让字符串可以包含原本需要转义的字符。这是#...#形式在主流语言中最重要的先例也是 Rust 未来若采用类似语法时可以直接借鉴的成熟设计。保留形式全景将 RFC 3101 与 RFC 3593 合在一起Rust 目前保留的未来语法空间可以归纳为下表保留形式出处引入 Edition说明identifier#identifierRFC 31012021如bar#quxidentifierstringRFC 31012021如barfooidentifiercharRFC 31012021如barfidentifier#numeric literalRFC 31012021如bar#123#STRING_LITERALRFC 35932024如#foo#、####foo####九、总结与展望RFC 3593 是一个小而关键的兼容性提案它不引入任何新语法、不改变任何现有语义只是把#foo#这块语法空间在 2024 Edition 中正式圈入保留区从而消除了宏 tokenize 行为在未来发生静默漂移的隐患。它的设计精髓可以概括为三点提前圈地与其等 RFC 3475 那样的语义提案在 Deadline 前仓促落地不如先把语法保留下来给未来语言演进留足时间与空间影响最小化对普通用户不可见仅在宏调用场景下产生分词错误且错误信息自带修复建议可自动迁移空白敏感的保留方式让 rustfix 能够机械地完成修复与 Rust 既有的cargo fix --edition工具链无缝衔接。展望未来这块被保留的语法空间可能被多种提案利用统一字符串字面量RFC 3475、无需前缀的新字面量类型、或者类似 Swift 扩展定界符的字符串特性。无论最终花落谁家RFC 3593 都确保了这一切可以在 2024 Edition 之后随时发生而无需再等待下一个 Edition 边界。对于宏作者而言记住一条铁律即可在宏调用中#与字符串字面量之间永远留一个空格。如需继续深入可以阅读本仓库中的相关文档RFC 3593 原文、RFC 3101 保留前缀、RFC 3348 C 字符串字面量、RFC 3085 Edition 2021 机制、RFC 3501 Edition 2024 规划以及 RFC 流程总览。赞分享文档【免费下载链接】rfcsRFCs for changes to Rust项目地址https://gitcode.com/gh_mirrors/rf/rfcs点击查看免费下载相关推荐Rust RFC 3101 解读2021 Edition 保留前缀Reserved Prefixes——为 Rust 未来语法预留空间的宏兼容性方案Rust RFC 3101 解读2021 Edition 保留前缀Reserved Prefixes——为 Rust 未来语法预留空间的宏兼容性方案 导读文档Rust RFC 3348 深度解读c… C 字符串字面量——CStr 字面量的设计、取舍与实现要点Rust RFC 3348 深度解读 c… C 字符串字面量—— CStr 字面量的设计、取舍与实现要点 本文基于 Rust 语言变更请求 RFC 33文档Rust 字面量后缀Literal Suffix前瞻性设计解读RFC 0463 如何为语言扩展预留词法空间Rust 字面量后缀Literal Suffix前瞻性设计解读RFC 0463 如何为语言扩展预留词法空间 导读 本篇基于 Rust RFC 仓库中的 R文档上一篇Akka.NET Persistence 存储插件完全指南Journal 与 Snapshot Store 的配置、启动与崩溃控制下一篇抖音下载神器3分钟掌握批量保存视频的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/16 2:20:00
CSAPP datalab位操作实战:从补码到饱和加法的底层思维训练
2026/10/16 2:20:00
C++抽卡模拟器源码解析:概率保底机制与二次开发实战
2026/10/16 2:20:00
用代码做视觉创作:artcraft类项目的技术选型与实战经验
2026/10/16 3:20:05
BERT中文文本分类实战:基于pytorch-transformers的完整工程与避坑指南
2026/10/16 3:20:05
Winpcap网络嗅探器实战:从抓包原理到协议解析与避坑指南
2026/10/16 3:20:05
Linux输出重定向完全指南:从文件描述符到Shell脚本实战
2026/10/16 3:20:05
PaddlePaddle手势识别实战:从训练到部署的完整指南
2026/10/16 3:20:05
BERT中文文本分类实战:从代码跑通到避坑进阶
2026/10/16 3:15:05
国产加速卡-应知应会
2026/10/16 0:04:49
HCIA-AI V3.5 模拟题库从零搭建:知识点标签、组卷算法与错题分析
2026/10/16 0:04:49
游戏项目Shader清理实战:静态扫描与动态验证双轨并行
2026/10/16 0:04:49
比特币白皮书深度拆解:从双重支付到共识机制的核心设计
2026/10/16 1:17:36
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/16 1:17:35
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/16 1:17:35
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/16 1:17:35
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/15 5:07:59
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/15 8:10:01
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)