当前位置: 首页 > 知识库问答 >
问题:

如何使用rust中的闭包创建迭代器?

谭裕
2023-03-14

我天真地试图这样做:

struct Foo<'a, S: Send, T:Send> {
    next_:Box<Fn<(&'a mut S,), Option<T>> + Send>,
    state:S
}

impl<'a, S: Send, T: Send> Iterator<T> for Foo<'a, S, T> {
    fn next(&mut self) -> Option<T> {
        return self.next_.call((&mut self.state,));
    }
}

要创建迭代器,我可以使用闭包轻松地发送到任务。

但是,它会产生可怕的寿命不匹配错误:

<anon>:8:33: 8:48 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
<anon>:8         return self.next_.call((&mut self.state,));
                                         ^~~~~~~~~~~~~~~
<anon>:7:5: 9:6 help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<T>
<anon>:7     fn next(&mut self) -> Option<T> {
<anon>:8         return self.next_.call((&mut self.state,));
<anon>:9     }
error: aborting due to previous error
playpen: application terminated with error code 101

我不明白这个错误。

闭包应采用生命周期为“a”的参数,即结构的生命周期。

国家为结构所有,因此其生命周期为“a”。

使用下一步。召唤((

所以这里的不匹配是下一个()中的自我终生和“呼叫中的a”之间的不匹配...但我不明白为什么它不是“a”。

修复上述代码的正确方法是什么?

有没有更好的方法来实现这一点?

游戏Geofence:http://is.gd/hyNi0S

共有3个答案

张智
2023-03-14

您可以使用itertools中的iterate,完全满足您的需要。

否则,如果要将所有逻辑包含在闭包中而不使用状态概念,则可以通过以下方式实现:

struct IterClosure<T, C>(C) where C: FnMut() -> Option<T>;

impl<T, C> Iterator for IterClosure<T, C> where C: FnMut() -> Option<T>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        (self.0)()
    }
}

fn iter<T>(f: impl FnMut() -> Option<T>) -> impl Iterator<Item=T> {
    IterClosure(f)
}

fn main() {
    let mut it = (0..10).into_iter();
    let mut closure = || it.next();
    println!("{}", iter(closure).sum::<i32>());

    let mut it = (0..10).into_iter();
    iter(|| it.next()).for_each(
        |i| println!("{}", i)
    )
}
黄向明
2023-03-14

这是当前锈菌特性系统的一个不幸限制,它将很快被解除。这是因为缺少更高级的生命。据我所知,它的实施目前正在进行中。

让我们更仔细地检查你的结构定义(我已经删除了mut,以允许使用'静态进行进一步的推理,这并没有使它不那么普遍):

struct Foo<'a, S: Send, T:Send> {
    next_: Box<Fn<(&'a S,), Option<T>> + Send>,  // '
    state: S
}

'a寿命参数是此处的输入参数。这意味着它是由结构的用户提供的,而不是由其实现者提供的。

(顺便说一句,它不是结构实例的生存期——你不能仅用类型参数指定这样的生存期;它必须是自我引用的生存期,你也不能使用它,因为迭代器特征方法没有寿命参数。然而,这只是一个附带说明,与实际问题无关)

这意味着结构的用户可以任意选择'a,包括选择大于结构生存期的生存期,例如'static。现在观察这样的选择是如何改变结构的(只需将'static替换为'a):

struct FooStatic<S: Send, T: Send> {
    next_: Box<Fn<(&'static S,), Option<T>> + Send>,  // '
    state: S
}

突然间,闭包只能接受'静态引用,这显然不是您的案例-Next()方法中自己的生存期可能会更短,所以您不能将其传递给闭包。只有当自己的生存期确实对应于'a(如编译器所建议的)时,这才能工作:

fn next(&'a mut self) -> Option<T>

然而,正如我前面所说的,你们不能写这篇文章,因为它会违反合同。

使用更高的生存期,可以在闭包本身上指定生存期参数:

struct Foo<S: Send, T: Send> {
    next_: Box<for<'a> Fn<(&'a mut S,), Option<T>> + Send>,
    state: S
}

通过这种方式,闭包的生命周期参数由闭包的调用方选择,在这种情况下,它是迭代器特征的实现者(即,您:),因此可以使用任何引用调用next,包括对Foo内部的引用。

黄宏大
2023-03-14

这需要更高的秩生存期,因为闭包中的生存期不应该是类型签名的一部分:闭包只想采用

需要明确的是:代码失败是因为next\uuu只能使用至少存在'a

您现在可以使用旧的闭包来解决这个问题(本质上这就是Fntrait对象),甚至还有一个标准的库类型可以为您实现这一点:Unfold

 类似资料:
  • 迭代器模式允许你对一个项的序列进行某些处理。迭代器(iterator)负责遍历序列中的每一项和决定序列何时结束的逻辑。当使用迭代器时,我们无需重新实现这些逻辑。 在 Rust 中,迭代器是 惰性的(lazy),这意味着直到调用方法消费迭代器之前它都不会有效果。例如,示例 13-13 中的代码通过调用定义于 Vec 上的 iter 方法在一个 vector v1 上创建了一个迭代器。这段代码本身没有

  • 为了决定使用哪个实现,我们需要知道哪个版本的 函数更快:直接使用 for 循环的版本还是使用迭代器的版本。 我们运行了一个性能测试,通过将阿瑟·柯南·道尔的“福尔摩斯探案集”的全部内容加载进 String 并寻找其中的单词 “the”。如下是 for 循环版本和迭代器版本的 search 函数的性能测试结果: 结果迭代器版本还要稍微快一点!这里我们将不会查看性能测试的代码,我们的目的并不是为了证明

  • 看看我制作的以下类: 以及它在以下方面的用法: 如果我使用,可能令人惊讶的是,我将永远得不到无限流。 相反,代码将在底层方法中创建时永远循环。 到目前为止,这是纯理论上的,但如果我想首先跳过无限流中的前x个数字,然后用最后的y个数字来限制它,我可以明确地理解它的必要性,如下所示: 代码不会返回一个结果,应该怎么做呢?

  • 是否可以从迭代器创建一个流,其中对象的序列与通过反复调用迭代器的next()方法生成的序列相同?我所考虑的具体情况涉及到Treeset.desceningIterator()返回的迭代器的使用,但是我可以想象在其他情况下,迭代器是可用的,而不是它所引用的集合。 例如,对于,我们可以编写并按照该集合的排序顺序获取该集合中的对象流,但是如果我们希望它们按照不同的顺序,比如通过使用获得的顺序呢?我想象的

  • 我使用的是swift软件包车载套件,它需要一个我无法理解的特定闭包类型。类<code>OnboardPage</code>要求参数<code>action</code>的类型为<code>OnboardPageAction</code>。 这是我最新的尝试,我沿着这些路线尝试了几种变体。 XCode 失败,并显示错误消息: 无法转换类型为'(Bool,Error?) - 我到底做错了什么?错误是在