[英]Issue with Rust using dynamic polymorphism on trait when specifying lifetime on self
[英]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
特性的情况下解决这个问题?
不。假设D
是Vec<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.