如何创建一个闭包来避免捕获变量的冗余克隆?
How do I make a closure that avoids a redundant clone of captured variables?
我正在尝试实现经典的 make_adder
函数,它接受一个可添加的东西和 returns 一个闭包,它接受另一个可添加的东西和 returns 总和。这是我的尝试:
use std::ops::Add;
fn make_adder<T: Add + Clone>(x: T) -> impl Fn(T) -> T::Output {
move |y| x.clone() + y
}
因为我不想将 T
限制为 Copy
,所以我在闭包内调用 clone()
。我认为这也意味着总会有一个冗余的 x
被闭包捕获为 "prototype"。我能以某种方式做得更好吗?
实际上,您无法避免这一点。你永远不知道闭包是否会在下一次被调用;您将需要保留该值以防万一。在分析确定这是一个瓶颈之前,我不会担心执行克隆。
在某些情况下,您可以将闭包类型更改为 FnOnce
,这会强制只能调用一次:
fn make_adder<T>(x: T) -> impl FnOnce(T) -> T::Output
where
T: Add,
{
move |y| x + y
}
在其他情况下,您也许可以为问题添加一些间接的方法。例如,不是传递 T
,而是传递一个生成 T
的闭包(大概不是通过克隆它自己捕获的变量...)。这个T
总是可以直接食用的:
fn make_adder<T>(x: impl Fn() -> T) -> impl Fn(T) -> T::Output
where
T: Add,
{
move |y| x() + y
}
如果您使用的类型支持引用加法(可能所有有用的类型都支持,包括内置数字类型),也许您可以使用引用。
fn make_adder<T, U>(x: T) -> impl Fn(T) -> U
where
for<'a> &'a T: Add<T, Output = U>,
{
move |y| &x + y
}
或
fn make_adder<'a, T>(x: &'a T) -> impl Fn(T) -> <&'a T as Add<T>>::Output
where
&'a T: Add<T>,
{
move |y| x + y
}
我正在尝试实现经典的 make_adder
函数,它接受一个可添加的东西和 returns 一个闭包,它接受另一个可添加的东西和 returns 总和。这是我的尝试:
use std::ops::Add;
fn make_adder<T: Add + Clone>(x: T) -> impl Fn(T) -> T::Output {
move |y| x.clone() + y
}
因为我不想将 T
限制为 Copy
,所以我在闭包内调用 clone()
。我认为这也意味着总会有一个冗余的 x
被闭包捕获为 "prototype"。我能以某种方式做得更好吗?
实际上,您无法避免这一点。你永远不知道闭包是否会在下一次被调用;您将需要保留该值以防万一。在分析确定这是一个瓶颈之前,我不会担心执行克隆。
在某些情况下,您可以将闭包类型更改为 FnOnce
,这会强制只能调用一次:
fn make_adder<T>(x: T) -> impl FnOnce(T) -> T::Output
where
T: Add,
{
move |y| x + y
}
在其他情况下,您也许可以为问题添加一些间接的方法。例如,不是传递 T
,而是传递一个生成 T
的闭包(大概不是通过克隆它自己捕获的变量...)。这个T
总是可以直接食用的:
fn make_adder<T>(x: impl Fn() -> T) -> impl Fn(T) -> T::Output
where
T: Add,
{
move |y| x() + y
}
如果您使用的类型支持引用加法(可能所有有用的类型都支持,包括内置数字类型),也许您可以使用引用。
fn make_adder<T, U>(x: T) -> impl Fn(T) -> U
where
for<'a> &'a T: Add<T, Output = U>,
{
move |y| &x + y
}
或
fn make_adder<'a, T>(x: &'a T) -> impl Fn(T) -> <&'a T as Add<T>>::Output
where
&'a T: Add<T>,
{
move |y| x + y
}