2015-10-01 41 views
1

我需要存儲相同結構的相同Vec實例,但具有不同的通用參數。這是結構定義:用於存儲具有不同通用參數的結構的特徵

struct Struct<'a, T: 'a> { 
    items: Vec<&'a T> 
} 

的結構有返回一個迭代器的類型不依賴於泛型類型參數T的方法:

impl<'a, T: 'a> Struct<'a, T> { 
    fn iter(&self) -> slice::Iter<&i32> { 
     unimplemented!() 
    } 
} 

我需要訪問這個方法對那些不同結構的載體,讓我實現了這個特點:

type Iter<'a> = Iterator<Item=&'a i32>; 

trait Trait { 
    fn iter(&self) -> Box<Iter>; 
} 

而且我已經實現了的特質對Struct

impl<'a, T: 'a> Trait for Struct<'a, T> { 
    fn iter(&self) -> Box<Iter> { 
     Box::new(self.iter()) 
    } 
} 

但是編譯器會抱怨:

<anon>:21:9: 21:30 error: type mismatch resolving `<core::slice::Iter<'_, &i32> as core::iter::Iterator>::Item == &i32`: 
expected &-ptr, 
    found i32 [E0271] 
<anon>:21   Box::new(self.iter()) 
        ^~~~~~~~~~~~~~~~~~~~~ 
<anon>:21:9: 21:30 help: see the detailed explanation for E0271 
<anon>:21:9: 21:30 note: required for the cast to the object type `core::iter::Iterator<Item=&i32> + 'static` 
<anon>:21   Box::new(self.iter()) 
        ^~~~~~~~~~~~~~~~~~~~~ 

我已經嘗試不同的可能性在性狀壽命參數,但他們沒有工作。我該如何做這項工作?

Rust Playground snippet

編輯

正如@MatthieuM指出。一個問題是類型別名工作不正常。這裏是另外一個例子證明這一點:

use std::slice; 

type Iter<'a> = Iterator<Item=&'a i32>; 

struct Struct<'a> { _phantom: std::marker::PhantomData<&'a i32> } 

impl<'a> Struct<'a> { 
    fn direct<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iterator<Item=&'a i32> 
    { i } 

    fn aliased<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iter<'a> 
    { i } 
} 

在這個例子中,direct編譯,但aliased不是,出現錯誤:

<anon>:12:7: 12:8 error: the type `core::slice::Iter<'a, i32>` does not fulfill the required lifetime 
<anon>:12  { i } 
       ^
note: type must outlive the static lifetime 

但他們似乎是同樣的事情。發生了什麼?

+0

我有一個類似問題的簡化測試用例:https://gist.github。com/59c6f269351efe805bcc =>從片轉換到Iterator '可以工作,但從片轉換到'Iter <'a>'並不是它只是前者的別名。 –

+0

@MatthieuM。好的,這似乎是問題所在。或者也許是問題的一部分?我應該編輯答案來解決這個小問題嗎? – mbrt

+0

我不認爲你需要編輯你的問題,這只是我沒有時間進一步進步,因此提交了我的結果,以防有人可以建立他們提交答案:) –

回答

2

問題1 - slice::Iter<T>Iterator::Item&T,因此您的參考水平不匹配。更改方法是

fn iter(&self) -> slice::Iter<i32> 

問題2 - Box<SomeTrait>相當於Box<SomeTrait + 'static>,但是你的迭代器不活了一輩子'static。您需要在一生中明確地將:

Box<SomeTrait + 'a> 

問題3 - 我不明白你怎麼能對一個特點,這似乎很奇怪創建一個類型別名。無論如何你可能不想要它。相反,創建整個盒裝版本類型別名:

type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>; 

問題4 - 重新整理main,這樣的引用會活得足夠長的時間,並增加可變性:

fn main() { 
    let i = 3; 
    let v = vec![&i]; 
    let mut traits : Vec<Box<Trait>> = Vec::new(); 
    traits.push(Box::new(Struct{ items: v })); 
} 

一起:

use std::slice; 

type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>; 

trait Trait { 
    fn iter<'a>(&'a self) -> IterBox; 
} 

struct Struct<'a, T: 'a> { 
    items: Vec<&'a T> 
} 

impl<'a, T: 'a> Struct<'a, T> { 
    fn iter(&self) -> slice::Iter<i32> { 
     unimplemented!() 
    } 
} 

impl<'a, T: 'a> Trait for Struct<'a, T> { 
    fn iter(&self) -> IterBox { 
     Box::new(self.iter()) 
    } 
} 

fn main() { 
    let i = 3; 
    let v = vec![&i]; 
    let mut traits: Vec<Box<Trait>> = Vec::new(); 
    traits.push(Box::new(Struct { items: v })); 
} 
+0

其中一個版本我嘗試過的'impl Trait'是這樣的:'fn iter(&self) - > Box ',但是編譯器抱怨'Iter'不是特性。所以,如果你輸入別名的特質,它不再是一個特質?我認爲類型別名就像C++別名和typedefs一樣,只有糖! – mbrt

+0

@brt是的,這是我所指的「*我不明白*」行的一部分。性狀確實有類型,這就是爲什麼你可以說'&SomeTrait'。儘管這些細節我有些模糊。 – Shepmaster

+0

很奇怪。也許這是另一個問題的材料。這爲我解決了。 – mbrt

相關問題