代码之家  ›  专栏  ›  技术社区  ›  Jeff Burdges

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

  •  0
  • Jeff Burdges  · 技术社区  · 7 年前

    是否有函数使用返回 Iterator<Item = &mut T> ?

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

    如果我们只需要对集合的确切元素进行迭代,那么我们可以使用 &mut C: IntoIterator 适用于所有生锈收集类型 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 .

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

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

    impl Trait 在特征上还没有解决,而且(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> 通过显式地将项的生存期绑定到 &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
    

    一个人应该如何返回一个 迭代器<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 回复  |  直到 7 年前
        1
  •  0
  •   Shepmaster Tim Diekmann    7 年前

    对于闭包,没有办法做到这一点,因为 Fn* 特征不支持将返回类型绑定到其生存期 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>;
    }
    

    'fn liftime语法类似 FnMut() -> impl Iterator<Item = &'fn mut Self> ,或者甚至可以使用参数化的类型参数 Args 作为 Args<'fn>

    推荐文章