有没有使用返回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
)来指定集合内容的“视图”。
直觉上,我们应该使用闭包借用集合,该闭包在调用时会重建我们的迭代器:
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
比迭代器的寿命更长。
我们应该通过&'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
实际上应该如何从作为参数传递的闭包中返回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() { }
}
答案 0 :(得分:0)
由于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>;
}
这些是不稳定的接口,因此它们可能最终可能会在RFC流程中进行更改,可能使用某些特殊的'fn
语法,例如FnMut() -> impl Iterator<Item = &'fn mut Self>
,甚至可能使用类型参数{{1} }设为Args
。 Rust内部构件是此问题的合适论坛。