簡體   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