首页/新闻资讯/正文详情

nom 2.0 升级指南:从 nom 1.x 迁移的完整破坏性变更清单与修复方案

发布时间:2026/9/24 17:09:17 来源:云帆数科 栏目:资讯中心
nom 2.0 升级指南:从 nom 1.x 迁移的完整破坏性变更清单与修复方案
nom 2.0 升级指南从 nom 1.x 迁移的完整破坏性变更清单与修复方案【免费下载链接】nomRust parser combinator framework项目地址: https://gitcode.com/gh_mirrors/no/nom导读本文基于 doc/archive/upgrading_to_nom_2.md 编写是 nom 1.x 用户迁移到 nom 2.0 的权威实操指南。nom 2.0 在引入大量新特性的同时对 1.x 中命名混乱的函数与宏、写法别扭的特性以及冗余功能进行了一次大清理因此带来了一批破坏性变更——不过其中大部分是无害的只需要机械地替换名称或调整写法即可。读完本文你将掌握如何通过 Cargo 特性开关适配新的错误系统、如何将eof函数替换为eof!()宏、如何处理基础解析器在空输入上返回Incomplete的新行为、如何迁移length_value!相关宏以及 endianness 参数如何从布尔值过渡到nom::Endianness枚举等全部变更点。背景说明当前仓库中的 nom 已演进到 8.0.0见 Cargo.toml本文记录的 2.0 变更属于历史升级路径中的关键一环。文中涉及的ErrorKind、Endianness、complete、Offset等概念至今仍是 nom 的核心设计结合当前源码可以更清晰地理解这些迁移背后的设计意图。Simple vs verbose errors错误系统被拆分为可选特性nom 1.0 的错误管理系统非常强大它允许你在解析树回溯backtracking时聚合错误并明确告诉你每个组合器处理了输入的哪一部分。但代价是性能为了在错误列表未被使用时将其丢弃编译器会生成大量额外代码拖慢了解析速度。并不是所有人都需要这一特性因此 nom 2.0 将它移到了一个名为verbose-errors的编译特性compilation feature之后。对于不使用Err枚举、不自定义错误码的项目升级到 2.0 后开箱即用即可直接编译通过并且在部分解析器上可以获得 30%50% 的性能提升该数据出自原文档。如果项目使用了旧错误系统编译时会看到类似下面的错误error: no associated item named Code found for type nom::ErrorKind_ in the current scope -- src/metadata/parser.rs:309:31 | 309 | _ IResult::Error(Err::Code( | ^^^^^^^^^ error: no associated item named Position found for type nom::ErrorKind_ in the current scope -- src/utility/macros.rs:16:41 | 16 | $crate::nom::IResult::Error($crate::nom::Err::Position( | ^^^^^^^^^^^^^^^^^^^^^^^^^^修复方式很简单在Cargo.toml中激活verbose-errors特性即可-nom ^1.0.0 nom { version ^2.0.0, features [verbose-errors] }如果项目只是用Err::Code来构造自定义错误码则可以考虑直接切到 simple errors2.0 用ErrorKindEu32类型直接替代了原来包含ErrorKindEu32的ErrInput, Eu32枚举也就是说错误码本身变成了错误类型不再需要外层枚举包装。从当前源码看这一演进方向被完整保留了下来如今 src/error.rs 中的ParseErrortrait 是错误系统的核心抽象所有解析器都泛型于实现了ParseErrorInput的错误类型而 src/error.rs 中的ErrorKind枚举Tag、Digit、LengthValue、Eof、Complete等则充当了统一错误码的角色。nom 还保留了(I, ErrorKind)元组错误类型和()空错误类型的 trait 实现src/error.rs以兼容早期代码——这与 2.0 simple errors 直接暴露ErrorKind 的迁移思路一脉相承。eof函数被移除替换为eof!()宏eof的原实现与输入类型耦合过深它需要了解输入的长度、是否为空等具体细节因此 2.0 将其改为宏组合器eof!()。如果你在升级时遇到以下错误error[E0432]: unresolved import nom::eof -- src/parser.rs:1:20 | 1 | use nom::{IResult, eof, line_ending, not_line_ending, space}; | ^^^ no eof in nom. Did you mean to use eol?修复方法是删除eof的导入并把所有eof调用替换为eof!()。-use nom::{IResult, eof, line_ending, not_line_ending, space}; use nom::{IResult, eol, line_ending, not_line_ending, space};有趣的是在当前版本中eof又以函数形式回归了见 src/combinator/mod.rs它检查input.input_len() 0输入为空时返回Ok((input, input))否则返回Err::Error且错误码为ErrorKind::Eof。这也印证了当年文档的判断——eof本质上只需要判断输入是否已耗尽完全可以做成语义清晰的独立组合器。基础解析器在空输入上改为返回Incompletealpha、digit、alphanumeric、hex_digit、oct_digit、space、multispace、sized_buffer这些基础解析器在 2.0 中遇到空输入时不再返回错误而是返回Incomplete。这一改动是为了让这些基础解析器行为更一致保持一致性的设计动机见原文档。如果你遇到下面的测试失败---- rules::literals::tests::case_invalid_hexadecimal_no_number stdout ---- thread rules::literals::tests::case_invalid_hexadecimal_no_number panicked at assertion failed: (left right) (left: Incomplete(Unknown), right: Error(Position(HexDigit, []))), source/rules/literals.rs:726可以用complete!组合器把Incomplete转换为Errornamed!(parse_hex[u8], [u8], complete!(hex_digit));这一流式/完整输入的语义区分在当今 nom 中依然是核心设计同一解析器存在 streaming 与 complete 两个版本。例如 src/character/streaming.rs 中的char在输入不足时返回Err::Incomplete(Needed::new(1))而 src/combinator/mod.rs 中的complete组合器则通过内部将模式切换为Complete把子解析器产生的Err::Incomplete(_)转换为Err::Error错误码为ErrorKind::Complete。如果你在升级 2.0 时用complete!包装了这些基础解析器这一迁移思路与 nom 后来按需选择 streaming/complete 版本的正式 API 是完全一致的。另外原文档特别提醒解析一个格式的基本元素例如某个 token 的字母表始终是高度定制化的这些通用函数未必总适合你的需求。这种情况下可以很容易地用take_while配合一个测试字符/字节的谓词函数来构造自己的解析器。take_till!改为按字节/字符迭代而非按它们的引用迭代2.0 要求输入类型符合新的 trait这带来了take_till!的行为变化谓词函数接收的参数从u8变成了u8。如果出现下面的类型不匹配错误error[E0308]: mismatched types -- src/linux/parser.rs:32:1 | 32 | named!(parse_c_string, take_till!(is_nul_byte)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found u8 | note: expected type u8 note: found type u8修复方法让谓词直接接收值而不是引用-fn is_nul_byte(c: u8) - bool { - *c 0x0 fn is_nul_byte(c: u8) - bool { c 0x0length_value!、length_bytes!重构length-value 模式通常表示先从输入中读取一个长度值再按该长度切出一段切片最后把这段切片转换成所需类型的值。在 nom 1.x 中length_value!宏用长度参数来控制 value parser 的执行次数——这个语义其实应该叫按长度计数与按长度取值并不相符。2.0 对此做了三处调整原length_value!宏被改名为length_count!保留按长度重复执行子解析器的语义新的length_value!宏先由第一个子解析器取得长度再切出该长度的切片然后在这段切片上应用第二个子解析器如果第二个解析器返回Incomplete整个解析失败新增length_data!从子解析器取得长度后直接返回该长度的子切片。典型迁移错误与修复如下error[E0308]: mismatched types -- src/tls.rs:378:37 | 378 | cert_types: cert_types, | ^^^^^^^^^^ expected struct std::vec::Vec, found u8 | note: expected type std::vec::Vecu8 note: found type u8fn parse_tls_handshake_msg_certificaterequest( i:[u8] ) - IResult[u8], TlsMessageHandshake { chain!(i, - cert_types: length_value!(be_u8,be_u8) ~ cert_types: length_count!(be_u8,be_u8) ~ sig_hash_algs_len: be_u16 ~在 TLS 握手消息这个例子中cert_types字段是一个1 字节长度 N 个 1 字节元素的数组需要的是按长度重复 N 次的语义因此改名为length_count!后行为完全正确。而如果你需要的是先读长度、再按长度取一段数据则对应新语义的length_value!或length_data!。这一命名上的纠偏让ErrorKind::LengthValue见 src/error.rs所代表的两种不同操作不再混为一谈。error!不复存在改名为return_error!1.x 中用于直接返回解析错误、不在解析树中回溯的error!宏在 2.0 中更名为return_error!。改名原因是log crate 也导出了一个error!宏而 log 的维护者选择向 nom 抱怨命名冲突原文档原话如此。同时add_error!宏也更名为add_return_error!。编译时可能出现的错误error: macro undefined: error! -- src/parser.rs:205:10 | 205 | error!(Custom(ParseError::InvalidData), | ^修复方式named!(repeatstr, u8, ParseError, - error!(Custom(ParseError::RepeatNotNumeric), fix!( return_error!(Custom(ParseError::RepeatNotNumeric), fix!( map_res!(flat_map!(take_s!(1), digit), FromStr::from_str))));注意示例中的用法return_error!的第一个参数是自定义错误Custom(ParseError::RepeatNotNumeric)这正是 nom 1.x/2.x 时期通过Err::Code(ErrorKind::Custom(...))携带自定义错误类型的典型写法。今天的 nom 已经把这一职责交给了ParseErrortrait 与ErrorKind::Custom见 src/error.rs 与 src/error.rs但显式返回自定义错误、跳过回溯的语义仍然存在。offset()方法移到OffsettraitHexDisplay只保留给字节切片nom 2.0 新增了Offsettrait并且为str也实现了该 trait而HexDisplaytrait 从此只保留给[u8]。在今天的源码中Offsettrait 依然位于 src/traits.rs其唯一方法fn offset(self, second: Self) - usize用于计算两个切片之间的字节偏移且要求第二个切片必须是第一个切片的一部分否则指针相减可能产生算术下溢。源码同时给出了[u8]的默认实现src/traits.rs通过指针相减计算偏移。如果你的代码依赖offset()方法升级时需要确保它来自nom::Offsettrait 的引入而不是旧版本的固有方法。AsChar::is_0_to_9改名为AsChar::is_dec_digit这是纯粹的一致性重命名AsChartrait 中判断十进制数字的方法从is_0_to_9改为is_dec_digit。迁移时只需全局替换方法名。可配置字节序的数字解析宏布尔参数改为Endianness枚举用布尔值表达字节序endianness容易引起混淆——true到底是大端还是小端因此 2.0 引入了nom::Endianness枚举数字解析宏的字节序参数从bool改为该枚举- named!(be_tst32u32, u32!(true)); - named!(le_tst32u32, u32!(false)); named!(be_tst32u32, u32!(Endianness::Big)); named!(le_tst32u32, u32!(Endianness::Little));这一设计一直沿用至今当前源码 src/number/mod.rs 中的Endianness枚举包含三个变体——Big大端、Little小端、Native与宿主机字节序一致后者是 2.0 时代没有的后续增强。而be_u8、be_u16、le_u32等固定字节序函数则是把这一枚举参数固化成了专用 API例如 src/number/mod.rs 中的be_u8。行结束符解析的统一在 1.x 中解析行结束符存在多种互不兼容的写法。2.0 统一了eol、line_ending和not_line_ending的行为先测试\n如果不对再测试\r\n。这修复了此前因换行符长度计算不一致导致的各类问题。// 现在 eol / line_ending 的行为一致 // 优先匹配 \n其次匹配 \r\n named!(parse_line_end, eol);迁移自检清单完成上述变更后可以用下面的清单快速核对升级是否彻底对照原文档的全部要点在Cargo.toml中确认已使用nom { version ^2.0.0, features [...] }并根据是否使用聚合错误决定是否启用verbose-errors全文搜索eof函数形式并替换为eof!()删除对应 import检查alpha/digit/space等基础解析器的调用点若依赖空输入即失败的语义用complete!包装take_till!的谓词签名从u8改为u8字符输入类推把按长度重复 N 次的length_value!改为length_count!按需改用新语义的length_value!或length_data!error!→return_error!add_error!→add_return_error!数字宏的字节序参数由true/false改为Endianness::Big/Endianness::Little若用到offset()确保通过Offsettrait 引入HexDisplay仅用于[u8]AsChar::is_0_to_9改为AsChar::is_dec_digit统一使用eol/line_ending解析行结束符先\n后\r\n。延伸阅读doc/archive/upgrading_to_nom_1.mdnom 1.0 升级指南可了解Err枚举泛型化、IResult生命周期消除、Incomplete行为调整等前置背景doc/archive/upgrading_to_nom_4.md 与 doc/archive/upgrading_to_nom_5.md后续大版本的迁移说明doc/error_management.md错误管理机制的完整介绍doc/choosing_a_combinator.md按场景选择合适的组合器src/error.rs当前ParseErrortrait 与ErrorKind枚举实现src/combinator/mod.rscomplete、eof等组合器的当前实现src/number/mod.rsEndianness枚举及数字解析函数examples/custom_error.rs自定义错误类型的完整示例。【免费下载链接】nomRust parser combinator framework项目地址: https://gitcode.com/gh_mirrors/no/nom创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Dopamine 分布投影详解:深入解析 `project_distribution` 与 C51 算法 Eq7 的实现
Dopamine 分布投影详解:深入解析 `project_distribution` 与 C51 算法 Eq7 的实现

Dopamine 分布投影详解:深入解析 project_distribution 与 C51 算法 Eq7 的实现 【免费下载链接】dopamine Dopamine is a research framework for fast prototyping of reinforcement learning algorithms. 项目地址: https://gitcode.com/gh_mirrors/do/dopami… · 2026/9/24 17:09:17

SDRPlusPlus Android后端NDK编译:从3条命令到完整ARM64构建
SDRPlusPlus Android后端NDK编译:从3条命令到完整ARM64构建

SDRPlusPlus Android后端NDK编译:从3条命令到完整ARM64构建 【免费下载链接】SDRPlusPlus Cross-Platform SDR Software 项目地址: https://gitcode.com/GitHub_Trending/sd/SDRPlusPlus SDR是一款跨平台的软件定义无线电软件,把手机变成能接收、… · 2026/9/24 17:09:11

用 Truffle 与 GraalVM 打造高性能 Mal 解释器:java-truffle 实现的渐进式优化实战
用 Truffle 与 GraalVM 打造高性能 Mal 解释器:java-truffle 实现的渐进式优化实战

示例工程 【免费下载链接】mal mal - Make a Lisp 项目地址: https://gitcode.com/gh_mirrors/ma/mal 点击查看 免费下载 本篇技术指南围绕当前仓库 mal(Make a Lisp)中的 java-truffle 实现展开:它用 Oracle 的 Truffle 框架在 … · 2026/9/24 17:09:11

数据分析最常用的9个模型,撑起80%的分析工作
数据分析最常用的9个模型,撑起80%的分析工作

做数据分析这些年,我越来越觉得,真正高频、真正能解决业务问题的分析模型,其实没有想象中那么多。刚开始做分析的时候,很容易有一种错觉:模型越高级,分析能力越强。于是很多人会去学回归、聚类、决策树、时… · 2026/9/24 17:54:40

相机之间的位置已知,为什么还要从头猜?浙大 G2G 用组内几何连接两组视觉观测(CoRL 2026)
相机之间的位置已知,为什么还要从头猜?浙大 G2G 用组内几何连接两组视觉观测(CoRL 2026)

「6%参数统一组间位姿估计」 目录 01 已知每组内部的关系,不等于知道两组如何对齐 02 现有方法的缺口:关键不只是“有没有几何”,还有“在哪里使用几何” 1. 先估计图像对,再聚合成组级结果 2. 多视图基础模型能联合看… · 2026/9/24 17:54:40

【架构专栏】第16章 嵌入式系统架构设计 3/3
【架构专栏】第16章 嵌入式系统架构设计 3/3

架构设计 相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 系统架构设计 相关文章: 【架构专栏】架构考试介绍 【架构专栏】架构知识点 知识总览​ 共19章内容,主要包括: 1)1绪论、2计算… · 2026/9/24 17:54:40

财务岗:先混进去,再谈专业
财务岗:先混进去,再谈专业

刚入行的时候,很多人都会把“专业”想得很复杂。证书要有,公式要熟,准则要背,Excel 要会,最好还能在面试时把成本核算、预算管理、合并报表和税务处理讲得头头是道。但真正进了公司才会发现,财务岗最先考验… · 2026/9/24 17:54:40

【架构专栏】第16章 嵌入式系统架构设计 2/3
【架构专栏】第16章 嵌入式系统架构设计 2/3

架构设计 相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 系统架构设计 相关文章: 【架构专栏】架构考试介绍 【架构专栏】架构知识点 知识总览​ 共19章内容,主要包括: 1)1绪论、2计算… · 2026/9/24 17:54:40

终于搞懂了!原来这才叫盈亏平衡分析
终于搞懂了!原来这才叫盈亏平衡分析

做经营分析久了以后,我发现“盈亏平衡”这个词几乎所有财务都听过,但真正拿到业务里会用的人,其实没有想象中那么多。很多人对盈亏平衡的理解还停在:收入刚好等于成本,不赚也不亏。这个定义当然没错。但如果只知道这一… · 2026/9/24 17:54:34

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码