closures - 返回在 Rust 中捕获外部变量的闭包

标签 closures rust lifetime

正如标题所述,我希望从具有一些初始可变状态的函数中返回一个闭包。在以下示例中,CowRow 是一个带有 time 字段的 struct。它还有一个 String 字段,因此不可复制。具体来说,我想要一个看起来像这样的函数:

pub fn agg1() -> Box<Fn(&CowRow)> {
    let res = 0;
    Box::new(move |r| { res += r.time; })
}

当然,这会产生错误:

src/queries.rs:9:25: 9:38 error: cannot assign to captured outer variable in an `Fn` closure
src/queries.rs:9     Box::new(move |r| { res += r.time; })
                                         ^~~~~~~~~~~~~
src/queries.rs:9:14: 9:41 help: consider changing this closure to take self by mutable reference
src/queries.rs:9     Box::new(move |r| { res += r.time; })
                              ^~~~~~~~

据我了解,Rust 需要知道返回值的大小,并且因为闭包从它们的环境中借用了它们的栈帧,所以我们需要引入 Boxmove获取返回的大小并将闭包放在堆上。

在这个闭包环境中,有没有什么方法可以将 res 也放在堆上?或者以其他方式允许这种行为?我当然看过:Cannot borrow captured outer variable in an `Fn` closure as mutable但这似乎过于复杂,我不清楚在多个线程同时运行此功能的情况下这将如何执行。

我尝试的另一种技术是更改闭包以获取对 i32 的可变引用,我可以在 agg 函数之外对其进行初始化。示例:

pub fn agg0() -> Box<Fn(&CowRow, &mut i32)> {
    Box::new(move |r, &mut acc| { acc += r.time; })
}

但是,这会产生错误:

src/queries.rs:4:35: 4:48 error: re-assignment of immutable variable `acc` [E0384]
src/queries.rs:4     Box::new(move |r, &mut acc| { acc += r.time; })
                                                   ^~~~~~~~~~~~~
src/queries.rs:4:35: 4:48 help: run `rustc --explain E0384` to see a detailed explanation
src/queries.rs:4:28: 4:31 note: prior assignment occurs here
src/queries.rs:4     Box::new(move |r, &mut acc| { acc += r.time; })

这对我来说完全是个谜。

最佳答案

你需要在这里做两件事:使 res 可变,并返回一个 FnMut 闭包,而不是 Fn 闭包:

pub struct CowRow {
    time: u64,
}

pub fn agg1() -> Box<FnMut(&CowRow) -> u64> {
    let mut res = 0;
    Box::new(move |r| { res += r.time; res })
}

fn main() {
    let mut c = agg1();
    let moo = CowRow { time: 2 };
    println!("{:?}", c(&moo));
    println!("{:?}", c(&moo));
    println!("{:?}", c(&moo));
}

Fn 特性禁止实现者在被调用时改变自身。因为这个闭包正在修改它自己的状态,这意味着它不能是 Fn [1]。相反,您需要使用 FnMut,它确实允许改变闭包捕获的环境。


[1]:当然,除非你涉及内部可变性。

关于closures - 返回在 Rust 中捕获外部变量的闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36511141/

相关文章:

rust - rust 生命周期参数必须超过静态生命周期

rust - 为什么 Vec<&str> 在这里缺少生命周期说明符?

closures - 在结构中存储闭包——无法推断出合适的生命周期

javascript - 动态生成带有闭包的js按钮来分配onclick函数参数

arrays - 如何在 Rust 中创建并传递以空字符结尾的 C 字符串数组 (char**)?

rust - 在 Rust 中,如何在格式中使用变量!宏?

rust - 如何将 `futures::Stream` 包装到任何实现 `Write` 的东西中?

rust - 在 for 循环中从 DirEntry 获取文件信息

python - 是否有一种 Pythonic 方式来关闭循环变量?

ios - 缺少闭包默认初始值设定项 - 快速闭包变量声明?