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

资讯详情

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

Rust 编译器错误 E0063 详解:结构体初始化时缺字段的诊断原理与修复方式

Rust 编译器错误 E0063 详解:结构体初始化时缺字段的诊断原理与修复方式 Rust 编译器错误 E0063 详解结构体初始化时缺字段的诊断原理与修复方式【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本篇围绕 rustc 错误码文档 E0063.md 展开讲清楚「结构体或类结构体枚举变体有字段未提供」这一错误的触发条件、诊断信息的完整格式单数/复数/截断三种形态并结合编译器类型检查源码 expr.rs 与实际回归测试 tests/ui/error-codes/E0063.rs 说明 rustc 是如何计算缺失字段并生成错误文本的。读完本文你不仅能正确修复 E0063还能理解诊断消息的生成逻辑与相关边界情况..更新语法、默认字段值、私有字段、non_exhaustive等。E0063 的语义每个字段必须恰好提供一次官方错误码文档的定义非常明确A structs or struct-like enum variants field was not provided.结构体或类结构体枚举变体的某个字段未被提供。原文档给出的错误示例struct Foo { x: i32, y: i32, } fn main() { let x Foo { x: 0 }; // error: missing field: y }文档同时给出了正确写法——每个字段应当被恰好指定一次Each field should be specified exactly oncestruct Foo { x: i32, y: i32, } fn main() { let x Foo { x: 0, y: 0 }; // ok! }这里有两个隐含规则值得强调不提供会报错E0063显式结构体初始化表达式必须覆盖全部字段重复提供也会报错字段被多次指定是另一条诊断FieldMultiplySpecifiedInInitializer不是 E0063但两者共同构成「恰好一次」的约束。真实诊断输出单数、复数与截断三种形态仓库中的回归测试 E0063.rs 特意构造了四种结构体分别覆盖单字段缺失、双字段缺失、以及缺失数量超过 3 个时的截断展示。其期望输出 E0063.stderr 展示了 E0063 消息的完整格式error[E0063]: missing field x in initializer of SingleFoo -- $DIR/E0063.rs:30:13 | LL | let w SingleFoo { }; | ^^^^^^^^^ missing x error[E0063]: missing fields y and z in initializer of PluralFoo -- $DIR/E0063.rs:32:13 | LL | let x PluralFoo {x: 1}; | ^^^^^^^^^ missing y and z error[E0063]: missing fields a, b, y and 1 other field in initializer of TruncatedFoo -- $DIR/E0063.rs:34:13 | LL | let y TruncatedFoo{x:1}; | ^^^^^^^^^^^^ missing a, b, y and 1 other field error[E0063]: missing fields a, b, c and 2 other fields in initializer of TruncatedPluralFoo -- $DIR/E0063.rs:36:13 | LL | let z TruncatedPluralFoo{x:1}; | ^^^^^^^^^^^^^^^^^^ missing a, b, c and 2 other fields error: aborting due to 4 previous errors For more information about this error, try rustc --explain E0063.可以归纳出三条格式规则缺失数量主消息span 标签1 个missing fieldxin initializer ofT| missing x2 个missing fieldsyandzin initializer ofT| missing y and z3 个全部列出全部列出超过 3 个只列前 3 个追加and N other field(s)同样截断注意测试中TruncatedFoo缺失 a、b、y、z 四个字段的消息是missing fieldsa,b,yand 1 other field——缺失字段名按排序后的顺序取前 3 个且field/fields、other field/other fields都会随数量做单复数变化。诊断末尾的固定提示For more information about this error, tryrustc --explain E0063.则指向 rustc 错误码文档体系本文所依据的 E0063.md 正是该体系的一个成员位于compiler/rustc_error_codes/src/error_codes/目录下每个错误码一个 Markdown 文件。源码剖析rustc 如何发现并报告缺失字段E0063 的完整生成链路位于 HIR 类型检查阶段核心函数是 check_expr_struct_fieldscompiler/rustc_hir_typeck/src/expr.rs。第一步建立「剩余字段」集合边检查边消耗类型检查开始时编译器先把变体variant的所有字段收集进一个 map作为「尚未提供」的集合let mut remaining_fields variant .fields .iter_enumerated() .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field))) .collect::UnordMap_, _();见 expr.rs 第 1900-1904 行。随后遍历初始化表达式中写出的每个字段若字段名能在remaining_fields中找到就remove掉并继续对该字段表达式做类型检查找不到则走另一条错误分支——字段名重复时报告FieldMultiplySpecifiedInInitializer否则报告未知字段report_unknown_field见 expr.rs 第 1934-1951 行。也就是说E0063 本质上是循环结束后remaining_fields非空的检测结果——凡是「定义里有、表达式里没写」的字段都留在这个集合中。第二步按表达式尾部形态分流遍历完成后编译器根据结构体表达式尾部StructTailExpr分四种情况处理见 expr.rs 第 2004-2263 行Base(expr)即..base函数式更新语法剩余字段由base的值补齐E0063 不会触发转而检查base表达式的类型DefaultFieldsbare..默认字段值这是 nightly 上的#![feature(default_field_values)]能力。若没有启用该特性报告的是另一条诊断BaseExpressionDoubleDot启用后只有「没有默认值且又没提供」的字段才会被单独报告为 mandatory 缺失NoneWithError表达式存在语法错误导致部分字段没解析出来时编译器只标记 tainted 而不报 E0063避免叠加虚假错误源码注释给出了StructName { foo(), bar: 2 }这类例子见 expr.rs 第 2211-2223 行None没有尾部这才是标准 E0063 路径。标准路径上的判断条件很典型rustc_hir::StructTailExpr::None { if adt_kind ! AdtKind::Union !remaining_fields.is_empty() !variant.field_list_has_applicable_non_exhaustive() { /* 报告缺失字段 */ } }见 expr.rs 第 2224-2262 行。两个守卫条件对应两个重要边界情况union 豁免union 初始化要求恰好一个字段字段数量不对时报告的是 E0784union expressions should have exactly one field见 expr.rs 第 1984-1992 行不落入 E0063non_exhaustive豁免带non_exhaustive标记的外部 crate 类型其字段集对外不完整源码中已注明「non_exhaustive 的缺失已由其他机制报告仅针对外部模块」注释//~ non_exhaustive already reported。第三步私有字段优先提示进入报告逻辑前还有一个可见性检查若缺失字段中存在对当前模块不可见的私有字段编译器改走report_private_fields而不是直接报 E0063let private_fields: Vecty::FieldDef variant .fields .iter() .filter(|field| { !field.vis.is_accessible_from(tcx.parent_module(expr.hir_id), tcx) }) .collect();见 expr.rs 第 2234-2249 行。这解释了实际开发中的一个常见体验跨模块漏掉私有字段时编译器倾向于先提示字段私有避免误导你直接去补一个根本不可见的字段。第四步消息文本的拼接与智能建议最终的错误构造在 report_missing_fieldsexpr.rs 第 2290-2367 行let displayable_field_names: Vecstr remaining_fields.items().map(|(ident, _)| ident.as_str()).into_sorted_stable_ord(); let remaining_fields_names match displayable_field_names[..] { [field1] format!({field1}), [field1, field2] format!({field1} and {field2}), [field1, field2, field3] format!({field1}, {field2} and {field3}), _ { truncated_fields_error format!( and {} other field{}, len - 3, pluralize!(len - 3)); displayable_field_names .iter() .take(3) .map(|n| format!({n})) .collect::Vec_() .join(, ) } }; let mut err struct_span_code_err!( self.dcx(), span, E0063, missing field{} {}{} in initializer of {}, pluralize!(len), remaining_fields_names, truncated_fields_error, adt_ty );这段代码与上一节归纳的三种消息格式一一对应字段名先排序into_sorted_stable_ord1/2/3/更多四种模式分别拼接超过 3 个时只取前 3 个并追加and N other field(s)pluralize!宏负责 field/fields 的单复数。struct_span_code_err!宏把错误码 E0063 绑定到诊断上从而让rustc --explain E0063能定位到对应的错误码文档。源码中还有两个进阶细节nightly 默认字段值建议如果所有剩余字段都带默认值field.value.is_some()且在 nightly 构建下诊断会附带一条机器可应用的建议——用..补齐并提示可启用#![feature(default_field_values)]见 expr.rs 第 2334-2360 行。注意这是nightly 实验特性稳定版不可用range 字面量误用建议若初始化表达式的最后一个「字段」写成了 range 字面量如a..b源码从结构看判断用户很可能想写..base会通过suggest_fru_from_range_and_emit发出改为函数式更新语法的建议见 expr.rs 第 2362-2366 行。与 E0063 相邻的边界情况速查结合上述源码路径可以把「初始化表达式字段不合法」的几个相邻错误码梳理清楚便于排错时快速区分场景错误码 / 诊断说明字段漏写无..E0063本文主题remaining_fields非空字段重复写FieldMultiplySpecifiedInInitializer「恰好一次」的另一半约束写了不存在的字段report_unknown_fieldE0027 系列字段名不在remaining_fields中union 表达式字段数 ≠ 1E0784union 豁免于 E0063对non_exhaustive外部类型构造StructExprNonExhaustive见 expr.rs 第 1847-1850 行漏写的是私有字段report_private_fields可见性检查优先于 E0063前序语法错误导致字段未解析不报 E0063仅标记 tainted防叠加误报修复建议直接补齐缺失字段错误消息已经把缺失字段名至多前 3 个 数量列出来按提示逐字段赋值即可这是原文档给出的标准解法使用..base函数式更新如果已有同类型或满足字段兼容约束的实例let y Foo { x: 0, ..old };可让剩余字段由old提供从根本上绕开 E0063。注意 stable 上..的基础表达式必须与外层是同一类型不同类型的基础表达式受type_changing_struct_update等实验特性控制源码中对同 ADT 判断见 expr.rs 第 2180-2194 行检查..与 range 字面量混淆如果消息附近附带 FRU 建议多半是把..base误写成了a..bnightly 用户可考虑默认字段值若字段都定义了默认值nightly 下可启用#![feature(default_field_values)]后使用 bare..编译器会自动给出该建议。小结E0063 是 rustc 对「结构体/类结构体枚举变体初始化必须覆盖全部字段」这一规则的强制检查其完整链路为check_expr_struct_fields 用remaining_fields集合差分出未提供字段 → 依据表达式尾部None/Base/DefaultFields/NoneWithError与 ADT 种类union、non_exhaustive、字段可见性分流 → 由 report_missing_fields 拼出带单复数与截断规则的 E0063 消息。行为与期望可对照仓库测试 tests/ui/error-codes/E0063.rs 与 tests/ui/error-codes/E0063.stderr 验证语义说明则出自错误码文档 compiler/rustc_error_codes/src/error_codes/E0063.md。理解了这条链路后遇到 E0063 既能快速修复也能准确判断编译器「该报没报」背后的守卫条件。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表