Rust闭包如何工作以及如何执行闭包? [英] How do Rust closures work and how does it execute a closure?
问题描述
它会创建一个新线程,然后在新线程内执行该匿名函数吗?
Does it create a new thread and then execute that anonymous function inside the new thread?
在处理封包时,我注意到许多所有权/借用限制.例如,如果我有Fn()
,则我无法在内部传递可变变量闭包,或者需要用Mutex
:
I noticed many ownership / borrowing restrictions when I'm working with a closure. For example, if I have Fn()
, I cannot pass a mutable variable inside the closure or it needs to be wrapped with a Mutex
:
fn helloworld(f: &Fn(f64)) {
f(42f64);
}
pub fn main() {
let mut killer = 2;
helloworld(&|n| {
println!("{}", n);
killer += 1;
});
}
如果像这样的闭包是不安全的,那么异步或并行操作就会在幕后发生,这就是为什么Rust编译器不允许我编译此类代码的原因.
If a closure can be unsafe like that then something asynchronous or parallel is going on behind the scene and that's why Rust compiler doesn't let me to compile such code.
我可能会感到困惑,因为我来自JavaScript/Python世界,那里的情况完全不同.
I might just be confused because I'm coming from a JavaScript / Python world and things are completely different there.
推荐答案
此问题分为两层.
首先,Rust中的闭包只是实现一个或多个可调用"特征的匿名定义类型.例如,这:
First, a closure in Rust is just an anonymously-defined type that implements one or more "callable" traits. For example, this:
fn main() {
let a = 6;
let closure = |b| {
println!("product is: {}", a * b);
};
closure(7);
}
被分解为类似于以下内容的东西:
is de-sugared into something similar to:
fn main() {
let a = 6;
let closure = {
struct Closure<'a> {
a: &'a i32,
}
impl<'a> Fn<(i32,)> for Closure<'a> {
extern "rust-call" fn call(&self, (b,): (i32,)) {
println!("product is: {}", (*self.a) * b);
}
}
impl<'a> FnMut<(i32,)> for Closure<'a> {
extern "rust-call" fn call_mut(&mut self, args: (i32,)) {
self.call(args)
}
}
impl<'a> FnOnce<(i32,)> for Closure<'a> {
type Output = ();
extern "rust-call" fn call_once(self, args: (i32,)) {
self.call(args)
}
}
Closure {
a: &a,
}
};
FnOnce::call_once(closure, (7,));
}
注意:以上代码依赖于不稳定的内部细节,因此无法在稳定的编译器上运行.提供它只是为了解释;您应该不自己使用此模式.
Note: the above code relies on unstable, internal details and will not work on a stable compiler. It is provided for explanation only; you should not use this pattern yourself.
不涉及线程,也没有神奇的事情发生.他们归结为带有额外的初始上下文"参数的常规函数调用.
There's no threading involved, and nothing magical is happening. They boil down to a regular function call with an extra initial "context" argument.
这将我们带到第二层,这就是您的特定代码不起作用的原因:因为您告诉编译器禁止这样做.可调用对象的一个关键问题是如何将上下文传递给可调用对象的代码.这由Fn
,FnMut
和FnOnce
特征表示(在问题
This brings us to the second layer, which is why your specific code doesn't work: because you told the compiler to forbid it. One critical concern for callables is how the context is passed to the callable's code. This is represented by the Fn
, FnMut
and FnOnce
traits (which are explained in the answer to the question When does a closure implement Fn, FnMut and FnOnce?). By taking &Fn(f64)
, you've restricted yourself to only accepting closures which require immutable access to their context.
如果希望闭包能够改变其上下文,则需要使用FnMut
.或者,如果只需要调用一次闭包,则可以使用FnOnce
(尽管不像在示例中那样作为特征对象).
If you want a closure to be able to mutate its context, you need to use FnMut
instead. Or, if you only need to call a closure once, you can use FnOnce
(although not as a trait object like you're doing in your example).
这篇关于Rust闭包如何工作以及如何执行闭包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!