我正在做一些关于生命周期和借阅判断器的实验.想象一下第一个 struct :

struct First {}

impl First {
    fn new() -> Self {
        Self {}
    }

    fn second(&self) -> Second {
        Second::new(self)
    }

    fn hello(&self) {
        println!("Hello");
    }
}

第二个,它的生命周期 限制取决于First:

struct Second<'a> {
    owner: &'a First,
}

impl<'a> Second<'a> {
    fn new(owner: &'a First) -> Self {
        Self { owner }
    }

    fn hello(&self) {
        self.owner.hello();
    }
}

上面的代码运行得非常好:Second是由First创建的,它不能比First更长寿.

问题

现在让我们修改Second,这样它就可以创建第三个 struct Third:

struct Second<'a> {
    owner: &'a First,
}

impl<'a> Second<'a> {
    fn new(owner: &'a First) -> Self {
        Self { owner }
    }

    fn third(&self) -> Third {
        Third::new(self.owner)
    }

    fn hello(&self) {
        self.owner.hello();
    }
}

Third本身,也取决于First:

struct Third<'a> {
    owner: &'a First,
}

impl<'a> Third<'a> {
    fn new(owner: &'a First) -> Self {
        Self { owner }
    }

    fn hello(&self) {
        self.owner.hello();
    }
}

我可以想象,当创建一个Third的实例时,它将依赖于First,但事实并非如此.实际上Third取决于Second:

fn main() {
    let f = First::new();
    let t = {
        let sss = f.second();
        sss.third() // error: sss does not live long enough
    };
}

那么,我如何使生命周期约束从First"通过"到Third

Full playground.

推荐答案

Rust有规则来推断函数的生命周期 :lifetime elision rules.

这些规则规定:

  • 参数中的每个省略生命周期 (i.e. a type that should had have a lifetime, but doesn't, like 100 that is actually 101)成为不同的生命周期 参数.
  • 如果参数中只使用了一个生存期(省略或不省略),则该生存期将分配给all个省略的输出生存期.

在方法签名中还有另一条规则

  • 如果接收器具有类型&Self&mut Self,则对Self的引用的生命周期 被分配给所有省略的输出生命周期 参数.

让我们以First::second()为例.其签名为:

fn second(&self) -> Second

或者,在明确省略所有生命周期 的情况下(顺便说一句,明确省略所有不在参考文献中的生命周期 被认为是一种良好的做法,如本例中的Second<'_>):

fn second(&'_ self) -> Second<'_>

所以根据规则#1,我们给&self分配一个新的生命周期,我们称之为'a:

fn second<'a>(&'a self) -> Second<'_>

现在,根据规则#3,我们为Second<'_> Select 'a:

fn second<'a>(&'a self) -> Second<'a>

也就是说,我们返回的Second与对self的引用具有相同的生存期.

现在我们把它应用到Second::third()...

fn third(&self) -> Third
// Becomes
fn third<'b>(&'b self) -> Third<'b> // Lifetime `'a` is already used

但这就是我们想要的!我们希望得到的Third取决于包含的First实例的生存期,而不是&self的生存期!所以我们真正需要的是使用Third<'a>:

fn third(&self) -> Third<'a> { ... }

现在it works beautifully岁.

Rust相关问答推荐

是否可以为`T:Copy`执行`T. clone`的测试

如何找到一个数字在二维数组中的位置(S)?

如何在Rust中实现Functor trait?

从特征实现调用函数的Rust惯用方法

将大小为零的类型实例存储到空指针中

带扫描的铁 rust 使用滤镜

取得本地对象字段的所有权

如何高效地将 struct 向量中的字段收集到单独的数组中

如何正确重新排列代码以绕过铁 rust 借入判断器?

我无法理解Rust范围的定义(Rust Programming Language,第二版克拉布尼克和尼科尔斯)

如何实现Deref;多次;?

获取已知数量的输入

为什么比较Option<;字符串>;具有常数Option<&;str>;需要显式类型转换吗?

在 Rust 中,是否可以定义一个需要实现类型的构造函数的对象安全特征?

我可以用 Rust 编写一个不可变变量

为什么要这样编译?

更好的方法来模式匹配带有 Rust 的窥视孔装配说明窗口?

我如何将 google_gmail1::Gmail> 传递给线程生成?

Rust:如果我知道只有一个实例,那么将可变borrow 转换为指针并返回(以安抚borrow 判断器)是否安全?

返回 &str 但不是 String 时,borrow 时间比预期长