Rust E0106 深度解析:missing lifetime specifier 错误的触发场景、省略规则与 rustc 源码实现
2026/9/7 8:23:29 网站建设 项目流程

Rust E0106 深度解析:missing lifetime specifier 错误的触发场景、省略规则与 rustc 源码实现

【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust

E0106 是 Rust 编译器在类型或函数签名中缺少生命周期标注(missing lifetime specifier)时报出的错误,它既覆盖“结构体/枚举/类型别名里的引用没写生命周期”,也覆盖“函数签名不符合生命周期省略(elision)规则”两类场景。本文以 Rust 官方的错误码解释文档为核心,结合 rustc 源码中诊断的生成位置,完整讲解该错误的触发规则、修复方式,以及rustc_resolve是如何定位并给出修复建议的。

E0106 是什么

E0106 的定义来自 E0106.md:

This error indicates that a lifetime is missing from a type. If it is an error inside a function signature, the problem may be with failing to adhere to the lifetime elision rules (see below).

也就是说,该错误有两种典型来源:

  1. 类型定义中遗漏生命周期:结构体、枚举、类型别名等“非函数”上下文中出现的引用(如&bool&str)必须显式携带生命周期,编译器不会为它们做任何省略推断;
  2. 函数签名违反省略规则:函数签名中的引用允许省略生命周期,但省略是受严格约束的有限推断,一旦不满足三条省略规则,同样会触发 E0106。

在错误码体系中,E0106 被登记在 error_codes! 宏列表 中(第 85 行附近的0106条目),该宏注释明确要求每个错误码对应一个error_codes/EXXXX.md解释文件,并受 tidy 的check_error_codes_docs检查约束——这正是本文所依据的文档存在的位置与格式规范。

场景一:类型定义中缺少生命周期参数

原文档给出的第一组示例覆盖了结构体、枚举、类型别名三种声明形式:

struct Foo1 { x: &bool } // ^ expected lifetime parameter struct Foo2<'a> { x: &'a bool } // correct struct Bar1 { x: Foo2 } // ^^^^ expected lifetime parameter struct Bar2<'a> { x: Foo2<'a> } // correct enum Baz1 { A(u8), B(&bool), } // ^ expected lifetime parameter enum Baz2<'a> { A(u8), B(&'a bool), } // correct type MyStr1 = &str; // ^ expected lifetime parameter type MyStr2<'a> = &'a str; // correct

这组代码体现了三条规律:

  • 直接包含引用的类型Foo1Baz1MyStr1):引用本身缺生命周期,错误指向&记号;
  • 引用了带生命周期参数的类型Bar1):Foo2声明为Foo2<'a>,使用时必须传入生命周期实参,Foo2后面的位置就是编译器提示“expected lifetime parameter”的地方,错误指向类型名本身;
  • 正确写法统一遵循一个原则:声明处添加生命周期参数(<'a>),使用处传入对应的生命周期实参。

从源码结构看,编译器对“缺失的生命周期”并非只有一种记录方式。MissingLifetimeKind 枚举区分了四种缺失形态:

pub enum MissingLifetimeKind { /// An explicit `'_`. Underscore, /// An elided lifetime `&' ty`. Ampersand, /// An elided lifetime in brackets with written brackets. Comma, /// An elided lifetime with elided brackets. Brackets, }

即显式写'_但位置不合法(Underscore)、&后完全省略(Ampersand)、括号内省略(Comma)、连括号都省略(Brackets)分别对应不同的诊断建议生成路径——这是后文修复建议能“贴合现场”的前提。

场景二:函数签名违反生命周期省略规则

原文档第二部分解释了 lifetime elision(生命周期省略):它是函数签名中一种“特殊的、受限的”生命周期推断机制,允许在特定情况下省略生命周期标注。其规则要求:任何返回生命周期被省略的函数签名,必须满足以下二者之一

  • 恰好只有一个输入生命周期(the output lifetime is inferred to be the same as the unique input lifetime);
  • 或者有多个输入生命周期,但该函数必须是方法,且接收者为&self&mut self(此时输出生命周期被推断为与self的引用生命周期相同)。

文档同时给出了三类违反省略规则的最小示例:

// error, no input lifetimes fn foo() -> &str { } // error, `x` and `y` have distinct lifetimes inferred fn bar(x: &str, y: &str) -> &str { } // error, `y`'s lifetime is inferred to be distinct from `x`'s fn baz<'a>(x: &'a str, y: &str) -> &str { }

逐条理解:

  • foo:没有任何输入生命周期,返回的&str无从推断——借用自谁都不存在;
  • barxy被推断为相互独立的生命周期,输出无法确定借用自哪一个;
  • baz:虽然x显式标注了'a,但y的省略生命周期被推断为与'a不同,因此候选仍然不唯一。

对应的修复方式是显式标注返回类型的生命周期,例如把bar改为fn bar(x: &str, y: &str) -> &str { x }这类情况需要显式写fn bar<'a>(x: &'a str, y: &str) -> &'a str,明确“返回值借用自x”。

源码溯源:E0106 诊断在哪里生成

E0106 的报错发生在名称解析的 late 阶段。rustc_resolve 的 late 解析器 维护一个current_elision_failures: Vec<(MissingLifetime, Either<NodeId, Range<NodeId>>)>字段(约 L805),在解析函数参数与返回类型时逐条记录“缺失的生命周期 + 相关节点”;解析完成后(约 L2488-L2507)取出这批失败记录并触发诊断。

真正组装错误信息的函数是 report_missing_lifetime_specifiers:

let mut err = struct_span_code_err!( self.r.dcx(), spans, E0106, "missing lifetime specifier{}", pluralize!(num_lifetimes) );

主诊断标题即missing lifetime specifier,并对每个缺失位置附加expected named lifetime parameter标签(多个时显示数量,如expected 2 lifetime parameters)——这正是文档示例中// ^ expected lifetime parameter注释的由来。

该诊断的 help 分支(diagnostics.rs)与省略规则一一对应,可以据此反推编译器的判定逻辑:

现场条件编译器给出的 help
函数参数中不存在任何被省略生命周期“this function's return type contains a borrowed value, but there is no value for it to be borrowed from”
存在被省略的生命周期,但不满足省略规则“…but the lifetime cannot be derived from the arguments”
候选输入生命周期恰好 1 个“…but the signature does not say whichxit is borrowed from”
候选输入生命周期多于 1 个“…but the signature does not say whether it is borrowed fromxory

此外,诊断还会根据当前作用域内已有的生命周期名称选择建议名(diagnostics.rs):作用域为空时建议'a,已有单个生命周期时复用其名称,否则建议'lifetime;并按MissingLifetimeKind生成不同的替换建议(对&&'a、对'_直接替换、对带括号的位置插入逗号分隔的多个生命周期等),这就是 rustc 能给出“可直接套用”修复建议的原因。

修复清单

结合文档示例与源码行为,修复 E0106 时可以按以下顺序操作:

  1. 结构体/枚举/类型别名:在声明处添加生命周期参数,在引用该类型的地方传入实参,对照前文Foo2/Bar2/Baz2/MyStr2的写法;
  2. 无参数函数返回引用:为返回类型指定'static或其他可推导的生命周期;若引用来自参数,为签名补充生命周期参数;
  3. 多参数函数返回引用:显式写出返回生命周期,并让它与某个参数的生命周期同名,明确“借用自哪一个输入”;方法场景可依赖&self省略规则;
  4. 复用编译器建议:rustc 的missing lifetime specifier诊断通常自带带具体名称的替换建议('_或补&'a),优先采纳建议、再结合语义确认借用来源是否正确。

参考位置

  • 错误码解释文档:E0106.md
  • 错误码登记表:rustc_error_codes/src/lib.rs
  • 诊断生成实现:rustc_resolve/src/late/diagnostics.rs、rustc_resolve/src/late.rs
  • 缺失生命周期分类:MissingLifetimeKind

【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询