我在处理结构的生命周期参数时遇到问题。我不是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正在通过移动传递,所以它应该正常工作吗?
有什么想法吗?感谢您的帮助。
答案 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
,但它可能不会在返回的值中存储对它的任何引用。
但是,您的方法定义使用的'a
将r
和返回的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
}。
当你不熟悉这些生活问题时很难想到;但随着时间的推移,它们变得非常自然。