2015-10-01 18 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

相关问题