【问题标题】:Why is a lifetime needed when implementing a trait on a reference type if the lifetime is otherwise unused, in Rust < 1.31?在 Rust < 1.31 中,如果生命周期未被使用,为什么在引用类型上实现特征时需要生命周期?
【发布时间】:2015-08-05 15:14:00
【问题描述】:

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

这是一个简单的例子。一个结构Inches,一个实现 Add 特征为 &amp;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 {
    ...
}

这终于可以正确编译了。

我的问题

为什么impl Add for &amp;Inches中的&amp;Inches被认为缺少一个 寿命说明符?告诉编译器解决什么问题 这个 Add 方法适用于&amp;Inches,带有一些未指定的非静态 生命周期'b,然后在任何地方都不要提及那个生命周期 还有吗?

【问题讨论】:

  • 'b 的生命周期在 + 操作中作为 'a 提供(当然是在编译时),允许编译器强制/确保 'b 到 'a 的生命周期要求,并且然后到main中的变量,对吗?因此,'b 本身并没有被使用,它是调用者(传递地)必须遵守的要求的表达。
  • 您的问题已经说明了它适用于哪个版本:我正在为引用类型实现一个特征使用 Rust 1.30

标签: rust lifetime


【解决方案1】:

Rust 1.31 及更高版本

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

现在,初始示例编译,您可以编写 impl Add for &amp;Inches 而不是 impl&lt;'b&gt; Add for &amp;'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 尝试过。原因是it's not implemented yet

对于这种情况,我 grep 了 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 实现完成!

【讨论】:

  • 我认为生命周期,即使被省略规则省略,在概念上仍然存在,必须由调用者提供和尊重,不是吗?
  • 生命周期仍然完全存在。省略规则指示编译器如何在编译时解决丢失的生命周期,避免您编写“明显的”样板注释。是的,它们必须受到调用者的尊重,但反过来,这些调用者可以从代码相关部分中的省略中受益。
  • 对。所以OP要问的一件事是明显的unspecified ... 'b,我的意思是它不是未指定的,在某种意义上调用者通过传入它来指定它(有效地在编译时,并且也由调用者的调用者传递)并且这与(文本)省略是否有效无关。当然,我可能误解了OP...
  • 感谢 @ErikEidt 和 mdup 如此仔细地阅读和回答我的问题。您的答案“必须始终有一个生命周期,无论是显式的还是推导的”(Erik)+“编译器还不能推断出这个”(mdup),一起回答了我的问题的两个部分“为什么要添加生命周期,以及为什么我不能忽略它'。谢谢你们。
  • 特别感谢您添加 RFC 和问题的链接。将新人指向主要来源和论坛对于教人们在哪里研究答案以及吸引人们进入社区非常宝贵。
猜你喜欢
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
  • 2019-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-22
  • 2019-02-24
相关资源
最近更新 更多