2017-03-01 21 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()) 
    } 
} 

它是由你來決定是否需要這個級別泛型與否。