Zoe*_*wll 3 closures higher-order-functions rust
我正在尝试创建一个函数来执行以下操作:接受f表单fn(T) -> T
的闭包返回表单的闭包,根据 bool 参数fn(T, bool) -> T有条件地执行f。
我来自 Haskell 的背景,在 Haskell 中,这将是这样的:
conditionally :: (a -> a) -> a -> Bool -> a
conditionally f x True = f x
conditionally f x False = x
Run Code Online (Sandbox Code Playgroud)
将其转换为更像铁锈的东西:
conditionally :: ((t) -> t) -> ((t, Bool) -> t)
conditionally f = \(x, b) -> if b then (f x) else (x)
Run Code Online (Sandbox Code Playgroud)
我在 rust 中尝试了以下操作:
fn conditionally<T>(f: &'static (dyn Fn(T) -> T + 'static)) -> Box<dyn Fn(T, bool) -> T> {
Box::new(&|x, b| if b { f(x) } else { x } )
}
Run Code Online (Sandbox Code Playgroud)
并被告知使用move关键字来确保闭包拥有f. 但是,以下仍然不起作用:
fn conditional<T>(f: &'static (dyn Fn(T) -> T + 'static)) -> Box<dyn Fn(T, bool) -> T> {
Box::new(&move|x, b| if b { f(x) } else { x } )
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误(这也出现在添加之前move):
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:216:5
|
216 | Box::new(&move|x, b| if b { f(x) } else { x } )
| ^^^^^^^^^^-----------------------------------^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
Run Code Online (Sandbox Code Playgroud)
我认为“当前函数拥有的数据”要么是我定义的闭包,要么f是我移动的闭包,但我无法理解它们是如何组合在一起的。
作为冒烟检查,我确保我能够装箱我在函数体中定义的更简单的闭包,并且以下编译:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:216:5
|
216 | Box::new(&move|x, b| if b { f(x) } else { x } )
| ^^^^^^^^^^-----------------------------------^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
Run Code Online (Sandbox Code Playgroud)
我在这里缺少什么?这在生锈中可能吗?我还想知道是否有比简单的高阶函数更具体的名称来说明我想要做的事情,因为我正在努力寻找有关此类问题的资源。
更新:我意识到“currying in rust”是一个很好的搜索词。虽然这不是柯里化的例子,但它会使用相同的语言特性,并且会引导我找到 vallentin 给出的答案。
您正在尝试返回对conditional函数中定义的闭包的装箱引用。你不能这样做,因为闭包只在通话期间有效。相反,您可以返回闭包本身,简而言之,只需删除&,即&move |x, b| ...变成move |x, b| ...。
fn conditional<T>(f: &'static (dyn Fn(T) -> T + 'static)) -> Box<dyn Fn(T, bool) -> T> {
Box::new(move |x, b| if b { f(x) } else { x })
}
Run Code Online (Sandbox Code Playgroud)
但是,编写您正在尝试的内容的更惯用的方法是使用泛型和闭包的类型参数。查看:
简而言之,您可以将其重写为:
fn conditional<F, T>(f: F) -> Box<dyn Fn(T, bool) -> T>
where
F: Fn(T) -> T + 'static,
T: 'static,
{
Box::new(move |x, b| if b { f(x) } else { x })
}
Run Code Online (Sandbox Code Playgroud)
您实际上也可以不使用该框,并使用impl Trait语法.
fn conditional<F, T>(f: F) -> impl Fn(T, bool) -> T
where
F: Fn(T) -> T,
{
move |x, b| if b { f(x) } else { x }
}
Run Code Online (Sandbox Code Playgroud)
您还可以使用impl Trait链接显示的参数语法,但我个人认为在处理关闭时它很嘈杂。
使用它归结为这样简单的事情:
let f = conditional(move |x| x * 2);
println!("{}", f(2, false)); // Prints `2`
println!("{}", f(2, true)); // Prints `4`
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
94 次 |
| 最近记录: |