尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Rust 编译器错误 E0026 深度解析:结构体模式解构不存在的字段(struct pattern)

Rust 编译器错误 E0026 深度解析:结构体模式解构不存在的字段(struct pattern) Rust 编译器错误 E0026 深度解析结构体模式解构不存在的字段struct pattern【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本文基于 Rust 官方仓库中错误码文档 E0026 展开完整覆盖该错误的触发场景、官方示例、正确写法并结合编译器源码说明 E0026 的诊断时机、报错调用链以及相似字段名自动修复建议的实现原理。读完后你不仅能正确理解并修复error[E0026]还能从编译器实现层面知道为什么字段名必须以冒号前的名字为准、编译器是如何发现模式字段不存在的以及相似名称建议是如何生成的。什么是 E0026模式匹配中提取不存在的结构体字段根据官方错误码文档的定义E0026 的语义只有一句话A struct pattern attempted to extract a nonexistent field from a struct.一个结构体模式试图从一个结构体中提取一个不存在的字段。也就是说当你用结构体模式struct pattern解构某个 ADTstruct、enum 变体、union时如果模式中写出的某个字段名在对应类型的声明中根本不存在编译器就会报error[E0026]。官方文档给出的错误代码示例如下struct Thing { x: u32, y: u32, } let thing Thing { x: 0, y: 0 }; match thing { Thing { x, z } {} // error: Thing::z field doesnt exist }注意这个示例的迷惑性模式里确实写了一个看起来像字段的z但Thing只有x、y两个字段。当前编译器以本仓库当前源码行为为准对这段代码的实际诊断输出为见 E0026.stderrerror[E0026]: struct Thing does not have a field named z -- $DIR/E0026.rs:9:23 | LL | Thing { x, y, z } {} | ^ struct Thing does not have this field error: aborting due to 1 previous error For more information about this error, try rustc --explain E0026.消息模板来自编译器诊断代码struct_span_code_err!( self.dcx(), spans, E0026, {} {} does not have {}, kind_name, tcx.def_path_str(variant.def_id), field_names );compiler/rustc_hir_typeck/src/pat.rs#L2320-L2328其中kind_name是 ADT 的描述词如structfield_names在单字段时是a field named \z多字段时会把不存在的字段名用fields named a, b 的形式合并列出见 pat.rs#L2303-L2318。也就是说如果你在同一个模式里写错了多个字段名它们会被合并进一条 E0026 诊断中而不是每个字段单独报一次错。核心规则字段以冒号前的名字识别缩写模式必须与声明一致这是 E0026 文档中最重要的规则性说明原文要点为结构体字段是以冒号:之前使用的名字来识别的因此结构体模式应当与被匹配结构体类型的声明保持一致。如果你使用的是缩写shorthand字段模式但又想把字段绑定到另一个名字的变量上就必须显式重命名。换句话说Rust 结构体模式Thing { x, y: z }中冒号前的名字x、y是字段名必须与类型声明中的字段名一致冒号后的绑定y: z中的z只是给解构出来的值取的局部变量名。因此当你要借用字段y的值到变量z时错误写法Thing { x, z }把变量名直接当字段名会触发 E0026正确写法应显式写出y: zstruct Thing { x: u32, y: u32, } let thing Thing { x: 0, y: 0 }; match thing { Thing { x, y: z } {} // we renamed y to z }这条规则的价值在于让模式可以逐字段与类型声明对齐阅读——模式写错的字段名一定是冒号前的那个。编译器如何发现字段不存在check_struct_pat_fields 流程E0026 并不是在解析或名称解析阶段报出的而是在类型检查typeck阶段处理结构体模式字段时发现的。核心调用链如下入口check_struct_pat_fields。类型检查器遍历模式中的每个PatField先构建一个字段标识符 → 字段索引与定义的哈希表field_mappat.rs#L2070-L2090// Index the struct fields types. let field_map variant .fields .iter_enumerated() .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field))) .collect::FxHashMap_, _();这里的键是字段标识符经过宏规范化处理这正对应文档中字段以名字识别的规则编译器拿模式中的ident去这个表里查。逐字段查表未命中即进入不存在清单。对每个模式字段若field_map中查不到该字段会被推入inexistent_fields向量.unwrap_or_else(|| { inexistent_fields.push(field); Ty::new_misc_error(tcx) })pat.rs#L2107-L2119。同时用used_fields记录已出现的字段防止同一字段被绑定两次那会报相邻错误码 E0025field bound multiple times in the pattern。决定是否报错。只有当inexistent_fields非空、且这些不存在字段里没有_下划线不是字段名时才调用error_inexistent_fields构造 E0026 诊断pat.rs#L2133-L2148。与 E0027 的协调。在错误聚合阶段如果同时出现了字段不存在错误和字段遗漏错误E0027编译器会先检查这是否其实是把元组变体tuple variant误用成了结构体模式——此时会改报error_tuple_variant_as_struct_pat的诊断并把 E0026/E0027 推迟为 bug 级别避免误导pat.rs#L2191-L2212。此外源码中有明确注释若已经对某字段报了 E0026就不会再为其追加 E0027pat.rs#L2359-L2362保证一条模式错误不会被重复诊断轰炸。编译器附赠的修复建议相似字段名匹配从源码结构看E0026 的诊断并非只报错error_inexistent_fields还会尽力给出可应用的Applicability::MaybeIncorrect修复建议pat.rs#L2329-L2384相似名建议当模式恰好漏写了某一个真实字段时编译器用find_best_match_for_name在不存在的字段名与未被提及的字段之间做最佳模糊匹配命中后提示a field with a similar name exists并直接建议替换成新字段名。例如把z写成z而真实字段叫zz之类的拼写偏差场景rustc 会直接建议改对。兜底建议如果模糊匹配未命中但对单个不存在字段而言存在某个真实字段类型可兼容也会给出{Variant} has a field named {name}的替换建议。元组结构体的特判若建议名可以被解析为数字如0、1说明用户很可能是把元组结构体Foo(a, b)用成了Foo { 0, 1 }这种结构体语法——此时跳过常规建议交由smart_resolve_context_dependent_help输出预期的元组语法建议pat.rs#L2354-L2359。另外若编译会话开启了教学模式tcx.sess.teach即--explain教学输出E0026 诊断还会附加一段教学性 note其内容正是官方错误码文档正文的浓缩版struct patterns should resemble the declaration of the struct type being matched…见 pat.rs#L2386-L2397。触发场景速查与相关错误码结合上述源码E0026 的典型触发场景及其与相邻错误的区分如下场景结果模式写字段名拼错Thing { x, y, z }E0026并可能附带相似名修复建议多个字段名同时写错一条 E0026字段名合并列出模式中把某个字段名写了两遍Thing { x: a, x: b }E0025字段被多次绑定模式漏写了必须覆盖的字段无..E0027未提及字段若已有 E0026 则不重复报 E0027元组变体误用结构体模式Foo { a, b }而Foo是元组 ADT优先报元组变体误用诊断E0026/E0027 被抑制模式中写_作为字段名不视为不存在字段跳过 E0026 检查官方测试与延伸阅读E0026 的行为由tests/ui/error-codes/下的官方 UI 测试固化E0026.rs / E0026.stderr主用例验证模式引用不存在字段时的诊断文本与位置标注E0026-teach.rs / E0026-teach.stderr教学模式teach用例验证--explain E0026时附加的教学 note 内容。错误码文档本身位于 compiler/rustc_error_codes/src/error_codes/E0026.md与rustc --explain E0026输出的说明同源。当你在本仓库rustc 源码树中调试模式匹配相关逻辑时可以直接从 compiler/rustc_hir_typeck/src/pat.rs 的check_struct_pat_fields入手沿着error_inexistent_fields追踪整条诊断链路。总结E0026 的判定发生在typeck 阶段由check_struct_pat_fields以模式字段名查field_map未命中为判据而非解析阶段修复原则只有一条结构体模式必须与类型声明逐字段对齐想要改变绑定变量名请使用字段名: 新变量名的显式重命名语法如Thing { x, y: z }编译器在报 E0026 时会做去重不与 E0027 冲突与纠错增强相似字段名建议、元组结构体语法建议善用这些建议可以一步修复拼写类错误。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表