如果在 Rust < 1.31 中未使用生命周期,为什么在引用类型上实现特征时需要生命周期?

Why is a lifetime needed when implementing a trait on a reference type if the lifetime is otherwise unused, in Rust < 1.31?

我正在使用早于 1.31 的 Rust 实现引用类型的特征。 当我告诉 Rust 我正在为哪种引用类型实现特征时,为什么 Rust 想要一个明确的生命周期?

这是一个简单的例子。一个结构 Inches,一个实现 Add &Inches 的特征,以及使用该实现的函数。

初始示例

(Rust playground link)

use std::ops::Add;

struct Inches(i32);

// this would work: impl<'b> Add for &'b Inches
impl Add for &Inches {
    type Output = Inches;

    fn add(self, other: &Inches) -> Inches {
        let &Inches(x) = self;
        let &Inches(y) = other;

        Inches(x + y)
    }
}

// lifetime specifier needed here because otherwise 
// `total = hilt + blade` doesn't know whether `total` should live
// as long as `hilt`, or as long as `blade`.
fn add_inches<'a>(hilt: &'a Inches, blade: &'a Inches) {
    let total = hilt + blade;
    let Inches(t) = total;
    println!("length {}", t);
}

fn main() {
    let hilt = Inches(10);
    let blade = Inches(20);

    add_inches(&hilt, &blade);
}

编译失败,出现以下错误:

error: missing lifetime specifier [E0106]
    impl Add for &Inches {
                 ^~~~~~~

我添加了缺少的生命周期说明符(仍然无法编译)

// was: impl Add for &Inches {
impl Add for &'b Inches {
    ...
}

编译错误:

error: use of undeclared lifetime name `'b` [E0261]
    impl Add for &'b Inches {

我在 impl 上声明生命周期(现在可以编译)

(Rust playground link)

// was: impl Add for &'b Inches {
impl<'b> Add for &'b Inches {
    ...
}

这最终编译正确。

我的问题

Why is &Inches in impl Add for &Inches considered to lack a lifetime specifier? What problem is solved by telling the compiler that this Add method is for &Inches with some unspecified non-static lifetime 'b, and then never referring to that lifetime anywhere else?

Rust 1.31 及更高版本

原因很简单:直到 Rust 1.31 才实现。

现在,初始示例编译,您可以编写 impl Add for &Inches 而不是 impl<'b> Add for &'b Inches。这是因为 1.31.0 stabilized new lifetime elision rules.

Rust 1.31 之前

如果您查看 RFC for lifetime elision,您会发现应该涵盖您的用例:

impl Reader for BufReader { ... }                       // elided
impl<'a> Reader for BufReader<'a> { .. }                // expanded

不过,我在游乐场试了一下,it doesn't work. The reason is that it's not implemented yet

我为这种情况搜索了 Rust 的源代码,但出乎意料的是它们很少。我只能在本机类型上找到 Add 的这一系列实现:

impl Add<u8> for u8
impl<'a> Add<u8> for &'a u8
impl<'a> Add<&'a u8> for u8
impl<'a, 'b> Add<&'a u8> for &'b u8

如您所见,这里的生命周期都是明确的;没有省略发生。

对于您的具体问题,我相信您必须坚持明确的生命周期,直到 RFC 实现完成!