用于存储具有不同通用参数的结构的特征

时间:2015-10-01 07:46:27

标签: rust traits

我需要存储在相同结构的相同Vec个实例中,但具有不同的通用参数。这是结构定义:

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

struct有一个方法,它将迭代器返回给不依赖于泛型类型参数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

但他们似乎是一回事。发生了什么?

1 个答案:

答案 0 :(得分:2)

问题1 - slice::Iter<T>的{​​{1}} Iterator::Item,因此您的参考级别不匹配。将您的方法更改为

&T

问题2 - fn iter(&self) -> slice::Iter<i32> 等同于Box<SomeTrait>,但您的迭代器不会在Box<SomeTrait + 'static>生命周期内存活。你需要明确地带来一生:

'static

问题3 - 我不明白如何为特征创建类型别名,这看起来很奇怪。无论如何,你可能不想要它。而是为整个盒装版本创建一个类型别名:

Box<SomeTrait + 'a>

问题4 - 重新排列type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>; ,以便引用能够存活足够长并增加可变性:

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