首页 文章

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

提问于
浏览
0

是否有任何使用闭包返回 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 . 此外,这不允许用户使用迭代器适配器(如 map )指定集合内容的"view" .

直观地说,我们应该使用一个在调用时重建迭代器的闭包来借用集合:

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

我们不能写那个因为(a)特征中的 impl Trait 问题尚未解决,(b)我们的 &mut Self 需要一辈子,所以我们可以写下:

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

我已经尝试过各种类似的配方,但没有一个工作,主要是因为 Item 比迭代器更长 .

我们应该通过明确地将项目的生命周期绑定到 FnMut 中的 &mut self 的生命周期来解决这个问题 &'a mut C: IntoIterator<Item = &'a mut T> . 在伪代码中:

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() { } 
}

1 回答

  • 0

    由于 Fn* traits不支持将返回类型绑定到其 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>;
    }
    

    这些是不稳定的接口,因此它们最终可能会通过RFC过程进行更改,可能使用一些特殊的 'fn 生命周期语法,如 FnMut() -> impl Iterator<Item = &'fn mut Self> ,或者甚至可能将参数化类型参数 Args 作为 Args<'fn> . Rust internals是这个问题的正确论坛 .

相关问题