迭代器的通用生命周期参数逐渐进入结构类型

Generic lifetime parameter of the iterator creeping into the struct type

我正在尝试创建一个数据结构(我们称之为 Outer)来包装另一个数据结构(我们称之为 Inner)。但是,我不想为 Inner 修复一个实现,而是想使用一个特征,这样我就可以轻松地交换这个底层数据结构的实现。

简化版看起来有点像这样:

pub struct Outer<K, V, I>
where
    I: Inner<K, V>
{
    inner: I,
    // some phantom data fields
}

pub trait Inner<K, V>
{
    ...
}

现在,我想给 Outer 添加一个迭代器,它也应该包装一个由内部数据结构提供的迭代器,问题就来了。

Inner 特征中,我不能写:

fn iter(&self) -> impl Iterator<Item = (&'_ K, &'_ V)>;

as impl Trait 语法在这里是不允许的,我也不能引入关联类型,如:

type Iterator<'a>: Iterator<Item = (&'a K, &'a V)>;

因为 generic associated types 还没有。

到目前为止我想到的是为迭代器设置一个单独的特征:

pub trait InnerIterator<'a, K: 'a, V: 'a>: Iterator<Item = (&'a K, &'a V)> {
    type Inner: Inner<K, V>;

    fn new(inner: &'a Self::Inner) -> Self;
}

然后Outer接收到一个新的泛型类型参数InnerIt:

pub struct Outer<K, V, I, InnerIt>
where
    I: Inner<K, V>
{
    inner: I,
    // some phantom data fields
}

impl<K, V, I, InnerIt> Outer<K, V, I, InnerIt> {
    pub fn iter<'a>(&'a self) -> InnerIt
    where
        I: Inner<K, V>,
        InnerIt: InnerIterator<'a, K, V, Inner = I>,
        K: 'a,
        V: 'a,
    {
        InnerIt::new(&self.inner)
    }
}

现在,当我想选择一些特定的 Inner 实现时,我有类似的东西:

pub type SomeOuter<'a, K, V> = Outer<K, V, SomeInner<K, V>, SomeInnerIterator<'a, K, V>>;

这里生命周期参数 'a 成为我的类型定义的一部分。

除了我必须添加至少两个参数以启用 iter_mutinto_iter 的问题之外,我的问题是拥有这个 'a 的后果是什么那里的参数,当使用这种类型时它会继续进一步传播吗?这种类型的用户会对这个生命周期参数感到惊讶吗?有没有一种方法可以在不引入通用迭代器类型及其 Outer 的生命周期的情况下实现迭代器?

would it continue to propagate further when using this type

任何想要嵌入您的类型的类型都需要有生命周期参数。 然而,有些地方生命周期省略将接管(例如在函数参数中):

struct Struct1<'a>(std::marker::PhantomData<&'a ()>);
struct Struct2<'a>(Struct1<'a>); // lifetime propagates to Struct2

fn func(_: Struct1){
    println!("lifetime not needed. It is 'elided'");
}

would the user of this type be surprised by this lifetime parameter

他们不应该。在铁锈中,生命无处不在。例如,迭代切片是使用 struct with a lifetime parameter.

完成的

is there a way to implement iterators without introducing generic iterator types and their lifetimes for Outer?

你有生命周期参数的原因是你有一个 return 引用的迭代器。如果您的迭代器 return 是一个直接对象,则不需要生命周期。例如,如果您将向量转换为迭代器(因此 return 包含向量中的所有元素)it won't need a lifetime parameter