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

Posted

技术标签:

【中文标题】爬入结构类型的迭代器的通用生命周期参数【英文标题】:Generic lifetime parameter of the iterator creeping into the struct type 【发布时间】:2021-06-30 05:11:03 【问题描述】:

我正在尝试创建一个包装另一个数据结构(我们称之为Inner)的数据结构(我们称之为Outer)。但是,我不想为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)>;

因为这里不允许使用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

【问题讨论】:

【参考方案1】:

使用这种类型时会不会继续传播下去

任何想要嵌入你的类型的类型都需要有一个生命周期参数。 但是,在某些地方,生命周期省略会接管(例如在函数参数中):

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'");

这种类型的用户会不会对这个生命周期参数感到惊讶

他们不应该。在生锈中,生命无处不在。例如,使用struct with a lifetime parameter 完成对切片的迭代。

有没有一种方法可以在不为 Outer 引入泛型迭代器类型及其生命周期的情况下实现迭代器?

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

【讨论】:

感谢您的回复。尽管如此,我仍然觉得这一生有些可疑,它在类型上,而不仅仅是在iter 方法上。它将传播到拥有我的数据结构的所有结构并不理想。哦,好吧,我想我会等待泛型关联类型并暂时移除 trait。

以上是关于爬入结构类型的迭代器的通用生命周期参数的主要内容,如果未能解决你的问题,请参考以下文章

如何在关联类型中指定生命周期参数?

为啥 Rust 编译器要求我限制泛型类型参数的生命周期(错误 E0309)?

PMBook 中的开发生命周期

为啥作为参数传递的特征对象的生命周期需要更高等级的特征边界,而结构不需要?

使用refs实现迭代器时的生命周期推断问题

uni-app页面生命与vue生命周期