我有一个带有盒装特征的结构 A
( Foo
),另一个结构 BoxedA
,其中有一个 Rc<RefCell<A>>
. 我正在尝试在 BoxedA
上创建一个方法,该方法将refrence返回到盒装特征,但在将 Ref<A>
映射到 Ref<Foo>
时仍会遇到生命周期问题 .
这是我的代码:
use std::rc::Rc;
use std::cell::{RefCell, Ref};
trait Foo {
}
struct A {
a: Box<Foo>
}
impl A {
fn new(a: Box<Foo>) -> A {
A { a: a }
}
fn a(&self) -> &Foo {
&*self.a
}
}
struct BoxedA {
a: Rc<RefCell<A>>
}
impl BoxedA {
fn new(a: Box<Foo>) -> BoxedA {
BoxedA {
a: Rc::new(RefCell::new(A::new(a)))
}
}
fn a(&self) -> Ref<Foo> {
Ref::map(self.a.borrow(), |a| a.a())
}
}
impl Foo for i32 {
}
fn main() {
let a = BoxedA::new(Box::new(3));
let a_ref = a.a();
}
Rust游乐场链接:https://play.rust-lang.org/?gist=d0348ad9b06a152770f3877864b01531&version=stable&backtrace=0
我得到以下编译错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> <anon>:34:41
|
34 | Ref::map(self.a.borrow(), |a| a.a())
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 34:38...
--> <anon>:34:39
|
34 | Ref::map(self.a.borrow(), |a| a.a())
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> <anon>:34:39
|
34 | Ref::map(self.a.borrow(), |a| a.a())
| ^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 33:28...
--> <anon>:33:29
|
33 | fn a(&self) -> Ref<Foo> {
| _____________________________^ starting here...
34 | | Ref::map(self.a.borrow(), |a| a.a())
35 | | }
| |_____^ ...ending here
note: ...so that the declared lifetime parameter bounds are satisfied
--> <anon>:34:9
|
34 | Ref::map(self.a.borrow(), |a| a.a())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
奇怪的是,代码编译,如果我用 i32
替换所有 Foo
.
1 回答
问题出在这个签名上:
通过终身省略规则,这扩展到:
哇,那是什么
+ 'b
位?Trait对象具有生命周期绑定,指定对象中包含的引用的最短生命周期 . 如果类型不包含任何引用,则该生存期限将为
'static
.如果在包含引用的类型上实现特征,例如一对引用:
然后你有一个
&Foo
类型的变量恰好是对(&'a u32, &'b u32)
的引用(要清楚,这是对一对引用的引用),哪里有关于两个&u32
引用的生命周期信息呢?这就是特质对象的生命周期所在的位置 . 完整的扩展类型&Foo
将看起来像&'c (Foo + 'd)
,其中'd
是'a
和'b
中的最短值(或者由于协方差而可能更短) .还有许多其他地方没有明确指定生命周期绑定 . 所有地方都希望函数的返回类型默认为
'static
生存期限 . 例如,struct A
中的Box<Foo>
会发生这种情况:它实际上被解释为Box<Foo + 'static>
.解决问题的简单方法是指定
A::a
返回一个带有'static
生存期限的特征对象:这很有意义,因为我们正在返回指向
Box<Foo + 'static>
内部的指针!BoxedA::a
可能最终会导致类似的问题,因此您可能也希望在使用它时修复此问题:现在您已经了解了这些生命周期边界,您可能想要考虑在该生命周期限制内使
A
和BoxedA
泛型是否有意义,而不是强制执行'static
. 如果您想最大化通用性,您的代码将如下所示:您可以自行决定是否需要此级别的通用性 .