Rust生命周期错误:预期具体生命周期,但找到绑定的生命周期

10

我在处理结构体的生命周期参数时遇到了问题。我不确定如何准确地描述这个问题,但是我创建了一个简单的示例来展示我的编译时错误。

struct Ref;

struct Container<'a> {
  r : &'a Ref
}

struct ContainerB<'a> {
  c : Container<'a>
}

trait ToC {
  fn to_c<'a>(&self, r : &'a Ref) -> Container<'a>;
}

impl<'a> ToC for ContainerB<'a> {
  fn to_c(&self, r : &'a Ref) -> Container<'a> {
    self.c
  }
}

我遇到的错误是

test.rs:16:3: 18:4 error: method `to_c` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 'a
test.rs:16   fn to_c(&self, r : &'a Ref) -> Container<'a> {
test.rs:17     self.c
test.rs:18   }
test.rs:16:48: 18:4 note: expected concrete lifetime is the lifetime 'a as defined on the block at 16:47
test.rs:16   fn to_c(&self, r : &'a Ref) -> Container<'a> {
test.rs:17     self.c
test.rs:18   }
error: aborting due to previous error

我尝试了许多变化,但就是无法编译它。我在这里找到了另一篇文章(如何解决:预期具体生命周期,但发现了绑定的生命周期参数),但它似乎是绕过问题而不是解决问题。我实在看不出问题甚至是从哪里开始的。&Ref通过移动被传递,所以它应该可以正常工作,对吧?

有什么想法吗?感谢所有的帮助。

1个回答

14

让我们比较这两个定义。首先是特质方法:

fn to_c<'a>(&self, r: &'a Ref) -> Container<'a>;

实现代码如下:

fn to_c(&self, r: &'a Ref) -> Container<'a>;

看到区别了吗?后者没有<'a><'a>在其他地方已经指定了;它具有相同的名称并不重要:它完全是另一种东西。

在功能上,您的trait定义表示返回的容器将内部引用来自r中的某个内容,但是不包含self中的任何内容。它可以在方法内部使用self,但不能在返回值中存储对它的任何引用。

然而,您的方法定义正在使用一个'a,将r和返回的Container的生命周期与self(也就是对象本身,而不是引用 - 在&'ρ₁ T<'ρ₂>中的 ρ₂——这是微妙但有时非常重要的区别)联系起来,而trait定义没有此类连接。

这两者可以通过在实现中的方法定义中插入<'a>来匹配。但请注意,这会遮蔽ContainerB<'a>中的'a,它不是同一个'a!我们最好给它另一个名称;为方便起见,我将更改反向地进行,将其更改为实现而不是方法(任何一种方法都可以):

impl<'b> ToC for ContainerB<'b> {
    fn to_c<'a>(&self, r: &'a Ref) -> Container<'a> {
        self.c
    }
}

但是现在您遇到了一个问题:返回值的类型是Container<'b>(因为一个ContainerB<'b>中的字段c的类型是这个),但是您的签名要求Container<'a>(使用来自r而不是self的引用)。

一种解决方法是在trait定义和实现中将&self的生命周期指定为'a;在实现中,这将要求'b大于或等于'a(因为您已经成功地使用生命周期'a对具有生命周期'b的对象进行了引用,并且对象必须比引用存在更长时间)因此由于子类型化('a'b的子类型),Container<'b>会被安全地转换为Container<'a>

当您不熟悉它们时,这些生命周期问题很难思考;但是随着时间的推移,它们会变得非常自然。


1
另一个修复方法是 trait ToC<'a> { fn to_c(&self, r: &'a Ref) -> Container<'a>; } - huon
哦,是的,然后是 impl<'a> ToC<'a> for ContainerB<'a> - Chris Morgan
这确实帮了很多,纠正了我一些错误的想法(例如lifetime shadowing)!谢谢。这个解决了这个问题,但是我似乎无法将其应用到另一个问题上。我在这里写了那个问题:http://stackoverflow.com/questions/24853111/rust-lifetime-error-expected-concrete-lifetime-part-2) - luke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接