我知道Lifetime in Iterator impl,但我想了解更多细节以帮助我正确理解。
我想要写一个返回Iterator
,&[0]
,&[0, 1]
等的无限&[0, 1, 2]
。我想写这个:
struct Countings(Vec<usize>);
impl Countings {
fn new() -> Countings { Countings(vec![]) }
}
impl Iterator for Countings {
type Item = &[usize];
fn next(&mut self) -> Option<Self::Item> {
self.0.push(self.0.len());
Some(self.0.as_slice())
}
}
我不能,因为类型Countings::Item
没有生命周期。
error[E0106]: missing lifetime specifier
--> src/lib.rs:8:17
|
8 | type Item = &[usize];
| ^ expected lifetime parameter
所以我加一个。它必须受impl Iterator
的约束。反过来,这需要struct Countings
上的生命周期参数。到目前为止,我在这里:
struct Countings<'a>(Vec<usize>);
impl<'a> Countings<'a> {
fn new() -> Countings<'a> { Countings(vec![]) }
}
impl<'a> Iterator for Countings<'a> {
type Item = &'a [usize];
fn next(&mut self) -> Option<Self::Item> {
self.0.push(self.0.len());
Some(self.0.as_slice())
}
}
现在我有一个不同的错误:
error[E0392]: parameter `'a` is never used
--> src/lib.rs:1:18
|
1 | struct Countings<'a>(Vec<usize>);
| ^^
|
= help: consider removing `'a` or using a marker such as `std::marker::PhantomData`
我认真考虑过:
use std::marker::PhantomData;
struct Countings<'a>(Vec<usize>, PhantomData<&'a [usize]>);
impl<'a> Countings<'a> {
fn new() -> Countings<'a> { Countings(vec![], PhantomData) }
}
impl<'a> Iterator for Countings<'a> {
type Item = &'a [usize];
fn next(&mut self) -> Option<Self::Item> {
self.0.push(self.0.len());
Some(self.0.as_slice())
}
}
但无济于事:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:14:25
|
14 | Some(self.0.as_slice())
| ^^^^^^^^
问题1:“冲突要求”是什么?
问题2:answer cited above表示Item
必须借用Iterator
包装的内容。我已经阅读了std::slice::Windows
的来源,这是一个很好的例子。但是,在我的情况下,我希望每次调用Vec
时都要改变next()
。这可能吗?
答案 0 :(得分:2)
问题1:&#34;冲突的要求是什么&#34;?
您尝试返回的借款没有承诺的终身'a
。相反,它与self
具有相同的生命周期。如果next
的签名是完整的,那就是:
fn next<'b>(&'b mut self) -> Option<&'a [usize]>
如果违反{{1}的合同,则返回Option<&'b [usize]>
(有效期为'b
而不是'a
)将有效。特质。但是,它会冻结Iterator
,直到结果被删除;即你不能两次拨打self
并同时使用两个电话的结果。这是因为每次调用next
都可能使先前返回的切片无效;推送到next
可以重新定位内存中的存储空间以便为其他元素腾出空间,因此切片中的指针将不再有效。
问题2:answer cited above表示
Vec
必须借用Item
包装的内容。我已经阅读了std::slice::Windows
的来源,这是一个很好的例子。但是,在我的情况下,我希望每次调用Iterator
时都要改变Vec
。这可能吗?
使用next()
特征无法做到这一点,因此您无法在结构上使用Iterator
循环。但是,您可以使用普通方法(上面提到的警告)来做到这一点。
for
答案 1 :(得分:2)
正如弗朗西斯所提到的,在迭代过程中无法修改基础向量。但是,如果你以某种方式有可能指定迭代界限,那么事情会容易得多:
[0, 1, 2, ...]
只是迭代器:
struct EverGrowingIterator<'a, T: 'a> {
slice: &'a [T],
current: usize,
}
impl<'a, T> Iterator for EverGrowingIterator<'a, T> {
type Item = &'a [T];
fn next(&mut self) -> Option<&'a [T]> {
if self.current >= self.slice.len() {
None
} else {
self.current += 1;
Some(&self.slice[0..self.current])
}
}
}
然后:
fn ever_growing<'a, T>(slice: &'a [T]) -> EverGrowingIterator<'a, T> {
EverGrowingIterator { slice: slice, current: 0 }
}
fn main() {
let v = vec![0, 1, 2];
for s in ever_growing(&v) {
println!("{:?}", s);
}
}
将打印:
[0]
[0, 1]
[0, 1, 2]
如果您需要对此进行调整以实现无限增长,则需要考虑创建一个自定义容器(不是Vec
),该容器将增长,同时保留对先前切片的引用。可以使用RefCell<Vec<Box<[T]>>>
之类的东西。