rust - 修改并返回闭包

标签 rust closures higher-order-functions

我正在尝试创建一个函数来执行以下操作: 接受 fn(T) -> T 形式的闭包 f 返回 fn(T, bool) -> T 形式的闭包,它根据 bool 参数有条件地执行 f

我来自 haskell-ish 背景,在 Haskell 中,这将是这样的:

conditionally :: (a -> a) -> a -> Bool -> a
conditionally f x True = f x
conditionally f x False = x

将其翻译成更像 rust 的东西:

conditionally :: ((t) -> t) -> ((t, Bool) -> t)
conditionally f = \(x, b) -> if b then (f x) else (x)

我在 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 } )
}

并被告知使用 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 } )
}

我收到以下错误(这也出现在添加 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

我在想'当前函数拥有的数据'要么是我定义的闭包,要么是我移动的f,但我想不通围绕它们如何组合在一起。
作为冒烟检查,我确保我能够装箱我在函数体中定义的更简单的闭包,并编译以下内容:

fn conditional_increment() -> Box<dyn Fn(i32, bool) -> i32> {
    Box::new(&|x, b| if b { x + 1 } else { x } )
}

我在这里错过了什么?这可能使用rust 吗? 我还想知道是否有比简单的高阶函数更具体的名称来表示我正在尝试做的事情,因为我正在努力寻找有关此类问题的资源。

更新:我意识到“currying in rust”是一个很好的搜索词。虽然这不是柯里化(Currying)的示例,但它会使用相同的语言功能,并且会引导我找到 vallentin 给出的答案。

最佳答案

您正在尝试返回对 conditional 函数中定义的闭包的装箱引用。你不能这样做,因为闭包只在通话期间有效。相反,您可以返回闭包本身,简而言之,只需删除 &,即 turn &move |x, b| ... 进入 移动 |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 })
}

但是,编写您尝试的内容的更惯用的方法是使用泛型和闭包的类型参数。查看:

简而言之,您可以将其重写为:

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

实际上你也可以不用盒子,使用 impl Trait syntax .

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 }
}

您还可以对参数使用 impl Trait 语法,如链接所示,但我个人认为它在处理闭包时噪音很大。

使用它可以归结为像这样简单的事情:

let f = conditional(move |x| x * 2);
println!("{}", f(2, false)); // Prints `2`
println!("{}", f(2, true));  // Prints `4`

关于rust - 修改并返回闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65527921/

相关文章:

Javascript - setTimeout 关闭问题

ios - Swift 闭包作为字典中的值

Haskell:了解与 lambda 函数一起使用时的映射函数

arrays - 有没有办法直接在堆上分配一个标准的 Rust 数组,完全跳过堆栈?

string - Rust 惰性静态自定义结构实例

javascript - 我什么时候应该使用 "that"的 Douglas Crockfords 实现?

python-3.x - 在嵌套函数中,如何让当前函数只粘附前一个函数的返回值?

java - 从 Java 调用 Kotlin 的高阶函数

mongodb - 如何使用 Rust MongoDB 驱动程序从添加到 GridFS 的文件中获取 ID?

indexing - 切片索引在 Rust 中如何工作?