iterator - 从闭包中返回并使用可变引用的迭代器

标签 iterator rust lifetime

是否有使用闭包返回 Iterator<Item = &mut T> 的函数示例? ?

我想编写几个 Rust 函数,对集合的内容进行多次迭代,并可能向后迭代。 IntoIterator单独是不够的,因为它按值消耗其参数以防止多次迭代。迭代器可以经常被克隆,但是可变引用的迭代器。

如果我们真的只需要对集合的确切元素进行迭代,那么我们可以使用 &mut C: IntoIterator适用于所有 Rust 集合类型 C .正在接受RFC 2289语法,这可能看起来像:

fn batch_normalization<II: ?Sized>(v: &mut II)
where
    for<'a> &'a mut II: IntoIterator<Item = &'a mut Self, IntoIter: DoubleEndedIterator + ExactSizeIterator>,

但是当前的表单遇到了一个 compiler bug .此外,这将不允许用户使用迭代器适配器指定集合内容的“ View ”,例如 map .

直觉上,我们应该使用闭包来借用集合,闭包在调用时重建我们的迭代器:

fn batch_normalization<F>(f: F)
where
    F: FnMut() -> impl Iterator<Item = &mut Self> + DoubleEndedIterator + ExactSizeIterator

我们还不能写那个,因为 (a) 关于 impl Trait 的问题in traits 尚未解决,并且 (b) 我们的 &mut Self需要一生,所以我们可以这样写:

fn batch_normalization<I, F: FnMut() -> I>(f: F)
where
    I: Iterator<Item = BorrowMut<Self>> + DoubleEndedIterator + ExactSizeIterator

我已经尝试过各种类似的公式,但没有一个很有效,主要是因为 Item比迭代器长。

我们应该以这种方式解决这个问题 &'a mut C: IntoIterator<Item = &'a mut T>通过将项目的生命周期显式绑定(bind)到 &mut self 的生命周期来实现在FnMut .在伪代码中:

fn batch_normalization<I, F: FnMut() -> I>(f: F)
where
    I: for<'a: F::Output> Iterator<Item = &'a mut Self> + DoubleEndedIterator + ExactSizeIterator

实际上应该如何返回 Iterator<Item = &mut T>来自作为参数传递的闭包?是否应该总是使用一些 fn指针困惑而不是闭包?大致:

fn batch_normalization<'a, I, V: ?Sized>(v: &mut V, f: fn(&'a mut V) -> I)
where
    I: Iterator<Item = &'a mut Self> + DoubleEndedIterator + ExactSizeIterator 
{
   for x in f() { }
   // ...
   for x in f().rev() { } 
}

最佳答案

没有办法用闭包精确地做到这一点,因为 Fn*特征不支持将返回类型绑定(bind)到它们的生命周期 self争论。现在,Fn*特质阅读

pub trait FnOnce<Args> {
    type Output;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
pub trait Fn<Args>: FnMut<Args> {
    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}

但这需要这些特征读起来像

pub trait FnOnce<Args> {
    type Output<'fn>;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output<'static>;
}
pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut<'fn>(&'fn mut self, args: Args) -> Self::Output<'fn>;
}
pub trait Fn<Args>: FnMut<Args> {
    extern "rust-call" fn call<'fn>(&'fn self, args: Args) -> Self::Output<'fn>;
}

这些是不稳定的接口(interface),因此它们最终可能会通过 RFC 过程进行更改,可能会使用一些特殊的 'fnFnMut() -> impl Iterator<Item = &'fn mut Self> 这样的liftime 语法,或者甚至可以使用参数化的类型参数 Args作为Args<'fn> . Rust internals 是解决这个问题的合适论坛。

关于iterator - 从闭包中返回并使用可变引用的迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51684123/

相关文章:

rust - 使用 map_keys 对扩展迭代器

c++ - STL迭代器重置

c++ - 显式调用析构函数

rust - 扩展 Rust 生命周期

rust - 当我重新分配链表的一半时,不再引用的 block 会发生什么?

c++ - 使用列表/迭代器 (C++) 的愚蠢编译错误

java - 使用迭代器时并发修改异常? ( java )

rust - 如何将函数推广到不同位置具有相似字段的两种类型?

Rust 将 trait 的实现依赖注入(inject)到另一个对象中

rust - 为什么 Rust 忽略 &str 的生命周期检查?