我在表达一个Iterator
实现的返回值的生命周期时遇到了麻烦。我如何在不改变迭代器的返回值的情况下编译这段代码?我希望它返回一个引用向量。
很明显,我没有正确地使用寿命参数,但是在尝试了各种方法之后,我放弃了,我不知道该怎么处理它。
use std::iter::Iterator;
struct PermutationIterator<T> {
vs: Vec<Vec<T>>,
is: Vec<usize>,
}
impl<T> PermutationIterator<T> {
fn new() -> PermutationIterator<T> {
PermutationIterator {
vs: vec![],
is: vec![],
}
}
fn add(&mut self, v: Vec<T>) {
self.vs.push(v);
self.is.push(0);
}
}
impl<T> Iterator for PermutationIterator<T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&T>> {
'outer: loop {
for i in 0..self.vs.len() {
if self.is[i] >= self.vs[i].len() {
if i == 0 {
return None; // we are done
}
self.is[i] = 0;
self.is[i - 1] += 1;
continue 'outer;
}
}
let mut result = vec![];
for i in 0..self.vs.len() {
let index = self.is[i];
result.push(self.vs[i].get(index).unwrap());
}
*self.is.last_mut().unwrap() += 1;
return Some(result);
}
}
}
fn main() {
let v1: Vec<_> = (1..3).collect();
let v2: Vec<_> = (3..5).collect();
let v3: Vec<_> = (1..6).collect();
let mut i = PermutationIterator::new();
i.add(v1);
i.add(v2);
i.add(v3);
loop {
match i.next() {
Some(v) => {
println!("{:?}", v);
}
None => {
break;
}
}
}
}
error[E0261]: use of undeclared lifetime name `'a`
--> src/main.rs:23:22
|
23 | type Item = Vec<&'a T>;
| ^^ undeclared lifetime
4条答案
按热度按时间whitzsjs1#
据我所知,你希望迭代器返回一个指向自身的引用向量,对吗?不幸的是,这在Rust中是不可能的。
这是
Iterator
的特征:注意,
&mut self
和Option<Item>
之间 * 没有生存期连接 *,这意味着next()
方法不能将引用返回到迭代器本身,你只是不能表达返回引用的生存期,这基本上就是你找不到一种方法来指定正确的生存期的原因--它看起来像这样:除了这不是用于
Iterator
特征的有效next()
方法。这样的迭代器(可以返回引用到自身的迭代器)称为 *streaming iterator *,如果需要,可以找到更多的here、here和here。
**Update.**然而,你可以从迭代器中返回一个对其他结构的引用--这是大多数集合迭代器的工作方式。
注意
'a
是如何在impl
块上声明的。这样做是可以的(事实上是必需的),因为你需要在结构上指定lifetime参数。然后你可以在Item
和next()
返回类型中使用相同的'a
。同样,这是大多数集合迭代器的工作方式。1dkrff032#
@VladimirMatveev的答案是正确的,它解释了为什么你的代码不能编译。简单地说,它说迭代器不能从它自己内部产生借来的值。
但是,它可以从其他东西中获得借用值,这就是
Vec
和Iter
所实现的功能:Vec
拥有这些值,而Iter
只是一个能够在Vec
中产生引用的 Package 器。这里有一个设计可以达到你的目的,迭代器就像
Vec
和Iter
一样,只是一个 Package 器, Package 了实际拥有值的其他容器。(Playground)
与您最初的问题无关。如果只是我,我会确保所有借用的向量都被一次获取。其思想是删除对
add
的重复调用,并在构造时直接传递所有借用的向量:(Playground)
(EDIT:已更改迭代器设计,以采用
Vec<&'a [T]>
而不是Vec<Vec<&'a T>>
。采用容器引用比构建引用容器更容易。)xe55xuns3#
正如在其他答案中提到的,这被称为 streaming iterator,它需要与Rust的
Iterator
不同的保证。一个提供这种功能的机箱被恰当地称为streaming-iterator,它提供StreamingIterator
特性。下面是一个实现trait的例子:
不幸的是,流迭代器将受到限制,直到RFC 1598中的generic associated types (GATs)被实现。
wyyhbhjk4#
不久前我写了这段代码,不知怎么的,我在这里偶然发现了这个问题,它做的正是这个问题所问的:它展示了如何实现一个迭代器来传递一个对自身的引用。
它为
IntoIterator
示例添加了一个.iter_map()
方法,最初我认为应该为Iterator
本身实现它,但这是一个不太灵活的设计决策。我为它创建了一个小板条箱,并将我的代码发布到GitHub上,以防您想尝试它,您可以使用can find it here。
虽然OP在为项目定义生命周期时遇到了麻烦,但在依赖默认的省略生命周期时,我在实现这一点时没有遇到任何这样的麻烦。
下面是一个用法的例子,注意回调函数接收的参数是迭代器本身,回调函数需要从迭代器中提取数据,然后直接传递或者执行其他操作。
因为
IntoIterMap
泛型trait是为IntoIterator
实现的,所以你可以从任何支持该接口的东西中得到一个“iter map”,例如,可以直接从一个数组中创建一个,如下所示:这是完整的代码--令人惊讶的是,它只需要这么少的代码就可以实现,而且所有的东西在组合起来的时候都运行得很顺利。这让我对Rust本身的灵活性和它的设计决策有了新的认识。