2017-03-01 22 views
3

我有一个结构A与盒装性状(Foo),另一个结构BoxedA它有一个Rc<RefCell<A>>。我试图在BoxedA上创建一个方法,该方法返回参考盒装特性,但在将Ref<A>映射到Ref<Foo>时仍然遇到有关生命期的问题。当使用Ref :: map与特征对象时,无法推断出生命周期

这里是我的代码:

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(); 
} 

锈操场链接: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()) 
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

奇怪的是,代码编译,如果我全部更换Foo的用i32

回答

2

的问题是与此签名:

fn a(&self) -> &Foo { ... } 

通过寿命省音规则,这将扩展为:

fn a<'b>(&'b self) -> &'b (Foo + 'b) { ... } 

哇,那是什么+ 'b位?

特征对象具有生命周期限制,指定对象中包含的引用的最短生命周期。如果该类型不包含任何参考,则该使用期限将为'static

如果实现在包含参考文献,例如一对引用的类型的特征:

impl<'a, 'b> Foo for (&'a u32, &'b u32) {} 

则必须恰好是一个​​参考&Foo类型的变量(将清楚,这是对一对引用的参考),关于两个&u32引用的生命周期信息去哪里了?这就是特质对象的使用期限。&Foo的完整扩展类型将看起来像&'c (Foo + 'd),其中'd'a'b(或可能更短,由于协方差)中最短的类型。

还有很多其他地方没有明确指定生命周期。所有地方期望返回类型的功能将默认为'static生命周期。例如,发生这种情况的原因是的struct A:它实际上被解释为Box<Foo + 'static>


最简单的解决问题的方法是指定A::a返回特质对象与'static一生的约束:

fn a(&self) -> &(Foo + 'static) { ... } 

这使得有很大的意义,因为我们正在返回一个指针一个Box<Foo + 'static>的内部!

BoxedA::a最终可能导致你类似的问题,所以你可能想得解决这个问题之一,而你在它:

fn a(&self) -> Ref<Foo + 'static> { ... } 

现在,您已经了解这些一生界,你可能需要考虑在该生命周期内ABoxedA是否通用,而不是强制执行'static。如果你想最大限度地提高通用性,你的代码应该是这样的:

struct A<'a> { 
    a: Box<Foo + 'a> 
} 

impl<'a> A<'a> { 
    fn new(a: Box<Foo + 'a>) -> A<'a> { 
     A { a: a } 
    } 

    fn a(&self) -> &(Foo + 'a) { 
     &*self.a 
    } 
} 

struct BoxedA<'a> { 
    a: Rc<RefCell<A<'a>>> 
} 

impl<'a> BoxedA<'a> { 
    fn new(a: Box<Foo + 'a>) -> BoxedA<'a> { 
     BoxedA { 
      a: Rc::new(RefCell::new(A::new(a))) 
     } 
    } 

    fn a(&self) -> Ref<Foo + 'a> { 
     Ref::map(self.a.borrow(), |a| a.a()) 
    } 
} 

它是由你来决定是否需要这个级别泛型与否。