锈蚀寿命误差预期具体寿命但发现约束寿命

时间:2014-07-20 04:20:47

标签: reference rust lifetime

我在处理结构的生命周期参数时遇到问题。我不是100%肯定如何描述问题,但我创建了一个显示编译时错误的简单案例。

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

我尝试了很多变化,但是无法编译这个东西。我在这里找到了另一篇文章(How to fix: expected concrete lifetime, but found bound lifetime parameter)但似乎解决了问题而不是解决问题。我真的不明白为什么问题甚至起源。 &amp; Ref正在通过移动传递,所以它应该正常工作吗?

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

1 个答案:

答案 0 :(得分:13)

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

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

实施:

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

看到区别?后者没有<'a>。其他地方已指定<'a>;它具有相同名称的事实并不重要:它完全是另一回事。

从功能上讲,您的特征定义表明返回的容器内部会有一个来自r的引用,但来自self 。它可能在方法中使用self,但它可能不会在返回的值中存储对它的任何引用。

但是,您的方法定义使用的'ar和返回的Container的生命周期与self相关联(即,对象本身,不是参考 - &'ρ₁ T<'ρ₂>中的ρ2 - 它是一个微妙的但有时是显着的差异),而特质定义没有这种联系。

通过在实现中的方法定义中插入<'a>,可以使两者匹配。但请记住,这会影响'a的{​​{1}};它是相同的ContainerB<'a>!我们最好给它另一个名字;为方便起见,我将进行相反的更改,在impl而不是方法上更改它(要么会这样做):

'a

但是现在你遇到了一个问题:返回值的类型为impl<'b> ToC for ContainerB<'b> { fn to_c<'a>(&self, r: &'a Ref) -> Container<'a> { self.c } } (因为Container<'b>中的字段c就是这样),但您的签名要求{{ 1}}(使用ContainerB<'b>的引用,而不是Container<'a>的引用。

解决这个问题的一种方法是在特征定义和实现中将r的生命周期指定为self;在实现中,这将要求&self大于或等于'a(由于您已成功将带有生命周期'b的引用带到具有生命周期的对象'a,并且该对象必须比引用更长)因此,由于子类型('a'b的子类型)'a,因此可以安全地强制转换为'b }。

当你不熟悉这些生活问题时很难想到;但随着时间的推移,它们变得非常自然。