将修改其环境的闭包传递给 Rust 中的函数
Passing a closure that modifies its environment to a function in Rust
我有一个捕获和修改其环境的闭包。我想将这个闭包传递给一个接受闭包的函数:
fn main() {
let mut integer = 5;
let mut closure_variable = || -> i32 {
integer += 1;
integer
};
execute_closure(&mut closure_variable);
}
fn execute_closure(closure_argument: &mut Fn() -> i32) {
let result = closure_argument();
println!("Result of closure: {}", result);
}
因为闭包修改了它的环境,所以失败了:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> src/main.rs:3:32
|
3 | let mut closure_variable = || -> i32 {
| ________________________________^
4 | | integer += 1;
5 | | integer
6 | | };
| |_____^
7 | execute_closure(&mut closure_variable);
| --------------------- the requirement to implement `Fn` derives from here
|
note: closure is `FnMut` because it mutates the variable `integer` here
--> src/main.rs:4:9
|
4 | integer += 1;
| ^^^^^^^
正如我从 中了解到的那样,这意味着我的闭包实际上被扩展为一个实现特征 FnMut
的结构。这个特征是可变的,意味着调用函数会改变(隐式)对象。我认为这是正确的,因为变量 integer
应该在调用 execute_closure()
.
之后修改
我如何让编译器相信这是可以的并且我真的想调用 FnMut
函数?或者我在这个例子中使用 Rust 的方式有什么根本性的错误吗?
如果你能改变接受闭包的函数...
接受 FnMut
而不是 Fn
:
fn main() {
let mut integer = 5;
execute_closure(|| {
integer += 1;
integer
});
}
fn execute_closure<F>(mut closure_argument: F)
where
F: FnMut() -> i32,
{
let result = closure_argument();
println!("Result of closure: {}", result);
}
如果不能更改接受闭包的函数...
等类型提供
use std::cell::Cell;
fn main() {
let integer = Cell::new(5);
execute_closure(|| {
integer.set(integer.get() + 1);
integer.get()
});
}
fn execute_closure<F>(closure_argument: F)
where
F: Fn() -> i32,
{
let result = closure_argument();
println!("Result of closure: {}", result);
}
Or is there something fundamentally wrong with how I use Rust in this example?
也许吧。 &mut Fn() -> i32
类型的参数不能改变它关闭的变量,所以错误消息对我来说很有意义。
它是 种类 类似于类型 &mut &u8
— 您可以更改外部引用以指向另一个不可变引用,但您不能 "ignore"内部不变性并更改数值。
旁白:
原始代码使用动态调度,因为有一个trait对象提供间接。在许多情况下,您会看到我上面发布的这个版本,它使用静态分派并且可以 单态化 。我还内联了闭包,因为这是正常的语法。
这是原始版本,只需进行足够的更改即可工作:
fn main() {
let mut integer = 5;
let mut closure_variable = || -> i32 {
integer += 1;
integer
};
execute_closure(&mut closure_variable);
}
fn execute_closure(closure_argument: &mut FnMut() -> i32) {
let result = closure_argument();
println!("Result of closure: {}", result);
}
我有一个捕获和修改其环境的闭包。我想将这个闭包传递给一个接受闭包的函数:
fn main() {
let mut integer = 5;
let mut closure_variable = || -> i32 {
integer += 1;
integer
};
execute_closure(&mut closure_variable);
}
fn execute_closure(closure_argument: &mut Fn() -> i32) {
let result = closure_argument();
println!("Result of closure: {}", result);
}
因为闭包修改了它的环境,所以失败了:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> src/main.rs:3:32
|
3 | let mut closure_variable = || -> i32 {
| ________________________________^
4 | | integer += 1;
5 | | integer
6 | | };
| |_____^
7 | execute_closure(&mut closure_variable);
| --------------------- the requirement to implement `Fn` derives from here
|
note: closure is `FnMut` because it mutates the variable `integer` here
--> src/main.rs:4:9
|
4 | integer += 1;
| ^^^^^^^
正如我从 FnMut
的结构。这个特征是可变的,意味着调用函数会改变(隐式)对象。我认为这是正确的,因为变量 integer
应该在调用 execute_closure()
.
我如何让编译器相信这是可以的并且我真的想调用 FnMut
函数?或者我在这个例子中使用 Rust 的方式有什么根本性的错误吗?
如果你能改变接受闭包的函数...
接受 FnMut
而不是 Fn
:
fn main() {
let mut integer = 5;
execute_closure(|| {
integer += 1;
integer
});
}
fn execute_closure<F>(mut closure_argument: F)
where
F: FnMut() -> i32,
{
let result = closure_argument();
println!("Result of closure: {}", result);
}
如果不能更改接受闭包的函数...
等类型提供use std::cell::Cell;
fn main() {
let integer = Cell::new(5);
execute_closure(|| {
integer.set(integer.get() + 1);
integer.get()
});
}
fn execute_closure<F>(closure_argument: F)
where
F: Fn() -> i32,
{
let result = closure_argument();
println!("Result of closure: {}", result);
}
Or is there something fundamentally wrong with how I use Rust in this example?
也许吧。 &mut Fn() -> i32
类型的参数不能改变它关闭的变量,所以错误消息对我来说很有意义。
它是 种类 类似于类型 &mut &u8
— 您可以更改外部引用以指向另一个不可变引用,但您不能 "ignore"内部不变性并更改数值。
旁白:
原始代码使用动态调度,因为有一个trait对象提供间接。在许多情况下,您会看到我上面发布的这个版本,它使用静态分派并且可以 单态化 。我还内联了闭包,因为这是正常的语法。
这是原始版本,只需进行足够的更改即可工作:
fn main() {
let mut integer = 5;
let mut closure_variable = || -> i32 {
integer += 1;
integer
};
execute_closure(&mut closure_variable);
}
fn execute_closure(closure_argument: &mut FnMut() -> i32) {
let result = closure_argument();
println!("Result of closure: {}", result);
}