
深入理解 Rust 编译器错误 E0164元组结构体模式为何只能匹配元组结构与元组变体【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rustE0164 是 rustc 在 HIR 类型检查阶段报告的模式匹配错误当你把一个既不是元组结构体、也不是元组变体的项如函数、关联函数、常量写成Path(args)形式的元组结构体模式时会触发它。本文从官方错误码文档出发给出可运行的错误与修正示例并结合 rustc 源码rustc_hir_typeck还原该错误从模式解析到诊断输出的完整调用链帮助你快速定位并修除此类模式书写错误。E0164 错误是什么rustc 错误码文档 E0164.md 对该错误的定义是一句话Something which is neither a tuple struct nor a tuple variant was used as a pattern. 某个既不是元组结构体、也不是元组变体的东西被当作模式使用了。文档给出的触发该错误的代码示例如下代码块标注compile_fail,E0164表示它应当编译失败且错误码恰为 E0164这与 rustc UI 测试套件对 compile-fail 测试的标注约定一致enum A { B, C, } impl A { fn new() {} } fn bar(foo: A) { match foo { A::new() (), // error! _ {} } }问题出在A::new()new是A的关联函数而不是某个元组变体的构造器。Path(args)这种带括号的模式在语法上属于元组结构体模式tuple struct patternrustc 只允许元组结构体或元组变体的构造器出现在这个位置因此报错。从编译器源码看实际的错误主消息由 rustc_hir_typeck 的诊断构造函数 生成模板为expected {expected}, found {res_descr} \{path_str}其中 E0164 对应的expected固定为字符串tuple struct or tuple variant见 [resolve_pat_tuple_struct](https://link.gitcode.com/i/f011f3756c8b45a4599d4ea5d13b64c4) 中的定义。也就是说上面的代码在较新版本的 rustc 中会得到类似expected tuple struct or tuple variant, found associated function A::new的诊断并且由于解析结果是Fn或AssocFn还会追加一条专门的 span 标注 fncalls are not allowed in patterns 以及一条指向 Rust 编程指南 Patterns 一书的帮助信息该特殊分支见 [report_unexpected_variant_res](https://link.gitcode.com/i/4d4614169fae21609358282dec55d6ef)条件是err_code E0164 且解析结果为函数或关联函数。正确写法只匹配变体本身文档给出的修正示例是把模式换成枚举变体路径A::Benum A { B, C, } impl A { fn new() {} } fn bar(foo: A) { match foo { A::B (), // ok! _ {} } }这里A::B是一个不带字段的枚举变体直接以路径模式path pattern形式出现即可不需要括号和子模式。作为对照合法的Path(args)形式只适用于以下两类定义元组结构体struct Pair(i32, i32);→Pair(a, b)是合法模式元组变体enum E { V(i32, i32) }→E::V(a, b)是合法模式。而带字段的结构体struct S { x: i32 }或单元结构体既不是元组结构体也不是元组变体写成S(..)、Unit(..)同样会落入 E0164 的路径其构造器路径的类型不是函数类型见下文源码分析。源码纵深E0164 的完整发射路径E0164 的判定发生在 HIR 模式类型检查pattern type-checking阶段整条调用链可以用三个关键位置串起来。1. 入口元组结构体模式的分发模式检查的总入口在rustc_hir_typeck的pat.rs中当遇到PatKind::TupleStruct时进入元组结构体路径的解析PatKind::TupleStruct(ref qpath, ..) Some(self.resolve_pat_tuple_struct(pat, qpath)),见 check_pat 的分发分支。注意只要源码写成Path(...)带括号的模式rustc 就会走这条“元组结构体模式”分支去解析路径——这正是A::new()这类函数调用写法会触发 E0164 的根源。2. 判定核心resolve_pat_tuple_structresolve_pat_tuple_struct 完成了 E0164 的触发判定关键逻辑有四处fn resolve_pat_tuple_struct(...) - ResultResolvedPattcx, ErrorGuaranteed { let report_unexpected_res |res: Res| { let expected tuple struct or tuple variant; let sub_pats match pat.kind { hir::PatKind::TupleStruct(_, sub_pats, _) sub_pats, _ [], }; let e self.report_unexpected_variant_res( res, None, sub_pats, qpath, pat.span, E0164, expected, ); Err(e) }; // ... }首先通过resolve_ty_and_res_fully_qualified_call完成路径解析与类型实例化判定一if !pat_ty.is_fn()即路径解析出的类型不是函数类型元组构造器必须是函数直接调用report_unexpected_res发射 E0164。常量、单元结构体、带字段结构体等都会走这里见 pat.rs#L1790-L1792判定二路径解析为关联常量AssocConst或关联函数AssocFn时发射 E0164。A::new()正属于此分支见 pat.rs#L1794-L1803唯一能通过的路径是Ctor(_, CtorKind::Fn)——即元组结构体/元组变体的构造器。此时编译器会把“构造器类型”替换为“被构造类型”pat_ty.fn_sig(tcx).output()继续对子模式做逐字段检查见 pat.rs#L1805-L1809。换句话说从源码结构看E0164 的语义边界非常清晰Path(args)形式的模式其路径必须解析为元组结构体或元组变体的构造器其余一切解析结果函数、关联函数、关联常量、普通常量、非元组类型等都会被拒绝。3. 诊断构造report_unexpected_variant_res错误信息的组装集中在FnCtxt::report_unexpected_variant_reslib.rs#L482-L612生成主消息expected tuple struct or tuple variant, found {res_descr} \{path_str}res_descr来自解析结果Res的描述枚举变体会显示为struct variantpath_str 是路径的完整文本若解析结果是函数/关联函数且错误码恰为 E0164则追加fn calls are not allowed in patterns的 span 标注并给出帮助信息指引读者查阅 Rust 书 Patterns 一章lib.rs#L503-L507同一函数中还为其他错误码如结构体误用的场景准备了更细粒度的模式改写建议例如建议补全字段名、建议添加括号等。E0164 在函数场景走的是上面的第一个分支说明编译器对“把函数当模式”这一高频误写做了专门的提示。常见触发形式一览结合源码判定逻辑可以整理出如下触发对照模式写法路径实际解析为结果A::new()关联函数AssocFnE0164附fn calls are not allowed in patterns标注free_fn()自由函数函数FnE0164同上A::CONST(...)关联常量AssocConstE0164CONST(...)普通常量常量类型非函数E0164UnitStruct(...)、NamedStruct(...)单元/带字段结构体E0164TupleStruct(a, b)、E::V(a, b)元组构造器Ctor(Fn)合法进入子模式检查如何在本地验证与定位复现错误将文档中的错误示例保存为单独文件后用rustc直接编译即可看到 E0164 诊断把A::new()改为A::B后代码即可通过编译与文档的修正示例一致。文档即测试E0164.md 位于rustc_error_codescrate 的error_codes/目录中该 crate 汇集 rustc 各错误码的说明文档文档内代码块使用compile_fail,E0164标注明确声明其“应当以该错误码编译失败”的测试语义。源码定位若你正在阅读 rustc 源码直接以E0164为关键词检索rustc_hir_typeck即可命中 pat.rs#L1773错误发射点与 lib.rs#L503函数类误用的特殊诊断分支两处核心位置。小结E0164 的本质Path(args)元组结构体模式的路径必须是元组结构体或元组变体的构造器函数、关联函数、常量等非构造器路径一律被拒触发点在 HIR 模式类型检查的resolve_pat_tuple_struct判定依据是“路径类型是否为函数”以及“解析结果是否为Ctor(Fn)”修复方法匹配变体/结构体值本身如A::B而不是调用它们的构造逻辑若确实想在match分支里执行构造或调用应在分支右侧或let语句中完成模式位置只描述“什么样的值”不描述“如何产生值”。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考