繁体   English   中英

Rust - 为借用特征指定生命周期参数

[英]Rust - Specifying a Lifetime Parameter for the Borrow Trait

我有一个包含一些数据( &[u8] )的结构( DataSource )和一个迭代它的自定义迭代器。

struct DataSource<'a> {
    data: &'a Vec<u8>,
}

struct MyIterator<'a> {
    source: DataSource<'a>,
}

impl<'a> Iterator for MyIterator<'a> {
    type Item = &'a u8;

    fn next(&mut self) -> Option<Self::Item> {
        let ret = &self.source.data[0];
        Some(ret)
    }
}

请注意这里的一些重要事项:

  • 迭代器的Item有生命周期。 这仅是可能的,因为该结构的字段之一已经使用了生命周期 - source
  • 编译器足够聪明,可以检测到由于Item的生命周期是'a ,所以ret的生命周期也必须是'a

现在,由于我的用例,我想添加以下功能:

  • DataSource也应该能够拥有自己的data
  • data不是Clone

我最初的解决方案是将data: &'a [u8]替换为data: D where D: Borrow<[u8]>

struct DataHolder<D: Borrow<[u8]>> {
    data: D,
}

struct MyIterator<D: Borrow<[u8]>> {
    holder: DataHolder<D>,
}

impl<D: Borrow<[u8]>> Iterator for MyIterator<D> {
    type Item = &u8;

    fn next(&mut self) -> Option<Self::Item> {
        Some(&self.holder.data.borrow()[0])
    }
}

我认为这会起作用,因为&[u8][u8]都实现了Borrow<[u8]> 但是,这不会编译。 迭代器的项目是&u8所以它需要一个明确的生命周期。 MyIterator没有任何生命周期可以引用,因此编写type Item = &'a u8会导致未声明的生命周期。

我的下一个解决方案是添加幻像数据并通过它引用生命周期:

struct DataHolder<'a, D: Borrow<[u8]>, T: 'a> {
    data: D,
    p: PhantomData<&'a T>,
}

struct MyIterator<'a, D: Borrow<[u8]>, T: 'a> {
    holder: DataHolder<'a, D, T>,
}

impl<'a, D: Borrow<[u8]>, T> Iterator for MyIterator<'a, D, T> {
    type Item = &'a u8;

    fn next(&mut self) -> Option<Self::Item> {
        Some(&self.holder.data.borrow()[0])
    }
}

这会产生以下错误:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src\bin\main7c.rs:16:26
   |
16 |         Some(&self.holder.data.borrow()[0])
   |                                ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src\bin\main7c.rs:15:10
   |
15 |     fn next(&mut self) -> Option<Self::Item> {
   |             ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src\bin\main7c.rs:16:9
   |
16 |         Some(&self.holder.data.borrow()[0])
   |               ^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src\bin\main7c.rs:12:6
   |
12 | impl<'a, D: Borrow<[u8]>, T> Iterator for MyIterator<'a, D, T> {
   |      ^^
note: ...so that the types are compatible
  --> src\bin\main7c.rs:15:43
   |
15 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
16 | |         Some(&self.holder.data.borrow()[0])
17 | |     }
   | |_____^
   = note: expected `<MyIterator<'a, D, T> as Iterator>`
              found `<MyIterator<'_, D, T> as Iterator>`

编译器无法推断返回值的生命周期必须与第一个示例中'a一样。 我可以解决这个放弃实现Iterator的问题,但这会破坏使用迭代器的全部意义。

impl<'a, D: Borrow<[u8]>, T> MyIterator<'a, D, T> {
    fn next(&'a mut self) -> Option<&'a u8> {
        Some(&self.holder.data.borrow()[0])
    }
}

有没有办法在不放弃Iterator特性的情况下解决这个问题?

有没有办法在不放弃Iterator特性的情况下解决这个问题?

不。假设DVec<u8> 终生'a什么?

当它已经是一个引用时,我们可以重用它的生命周期。 这是因为,假设data&'a T&self.data[0] where self is &'b mut self可以看作(伪Rust):

let slice_data_pointer: &'a u8 = (*self.data);
slice_data_pointer

也就是说,我们只是复制引用。

但是当拥有data时,就没有要复制的引用了。 唯一的真实来源是self.data本身 - 而self.data仅在self的生命周期内被借用。 所以你需要迭代器的产生值依赖于next()self 这是经典的借贷/流式迭代器,它:

  • 标准库中不存在。
  • 需要通用关联类型(这是它不在标准库中的部分原因)。
  • 任何时候只允许一个产生的值存在——它们不能共存,因为它们都可变地从不同生命周期的self借来。 换句话说,它不能实现像collect()这样的操作。

但是,我们可以从实际Vec实现Iterator的方式中学习。 具体来说,它不会 - 通常拥有值也是如此 - 它们实现IntoIterator来代替对它们的引用,可能使用iter()方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM