什么条件可以使闭包实现Fn
,FnMut
和FnOnce
特性?
具体而言:
- 何时闭包不会实现
FnOnce
特性? - 何时闭包不会实现
FnMut
特性? - 何时闭包不会实现
Fn
特性?
例如,在闭包内部修改其状态将使得编译器不能在其上实现Fn
。
call_...
方法的签名以及特别是self
的类型指示:
闭包|...| ...
将自动实现它所能实现的内容。
FnOnce
:不能被调用一次的闭包不会被称为闭包。请注意,如果闭包只实现了FnOnce
,它只能被调用一次。FnMut
,允许它们被调用多次(如果有未别名化访问函数对象的方式)。Fn
,允许在基本上任何地方调用它们。这些限制直接遵循self
的类型以及将闭包展开成结构体的“解糖”过程;详见我在博客文章Finding Closure in Rust中的描述。
有关闭包的信息,请参见The Rust Programming Language中的闭包:可以捕获其环境的匿名函数。
FnOnce
”。 - sleeparrowFnOnce
。这个特质的名称令人困惑。 - Paul Razvan BergFnOnce
中的“Once”指的是调用者将调用它的上限次数,而不是它可以被调用的次数。Fn
:
FnMut
:
Fn
特质的作用。正如 op 所指出的:“在闭包体上改变闭包状态会导致编译器不将其实现为 Fn
。”)FnOnce
:
(所有这些特征只是编译器确定在哪里可以使用任意闭包,同时保持闭包操作数据的内存处于“安全”状态的一种方式)
— 一些示例:
(注意:{{link1:我无法使用“impl”类型对“updated_vec”进行注释},所以我将在绑定定义附近的注释中指定由rust-analyzer推断的类型)
Fn
特性:fn main() {
let some_vec = vec![1, 3, 4];
let get_that_same_vec = || { // "get_that_same_vec" type: impl Fn() -> &Vec<i32>
&some_vec
// as you can see the closure is specified to implement the *Fn* trait,
// meaning it can be called however many times since it doesn't alter the data it operates on
// or pass the ownership of that data to any other entity
};
// - By using the "&" above we are basically saying that a closure should just return a reference to a value.
// - If we were to omit the "&" above, we would basically be saying:
// "return and pass the ownership of this value to whomever decides to invoke this closure"
// which would basically be like turning it into an infinite generator of that value and its ownership
// "Oh, another caller wants this value and the ownership of it? Sure, let me take the copy of that value... out of thin air I guess!"
// As you can figure, Rust doesn't allow for that last sentence to be true,
// since that would allow multiple entities to have the ownership of the underlying memory,
// which would eventually result in a "double free" error when needing to free that underlying memory when one of the owners goes out of scope. (see: *FnOnce* example)
println!("This is the vec: {:?}", get_that_same_vec());
println!("This is the vec: {:?}", get_that_same_vec()); // if "&" would not be present above, then this would not compile
}
FnMut
:(为什么我们需要用"mut"标记持有FnMut
闭包的变量,请参阅这个很棒的答案)
fn main() {
let mut some_vec = vec![1, 3, 4];
let mut update_vec = || { // "update_vec" type: impl FnMut()
some_vec.push(5);
};
// As you can see the closures that implement the *FnMut* trait can be called multiple times,
// because they do not pass the ownership of the data they capture out of their scope
// they only alter its state, and if altering the value of its state multiple times is a legal operation
// for a type on which the closure operates, then it is surely ok to call such a closure multiple times
update_vec();
update_vec();
println!("This is the updated \"some_vec\": {:?}", some_vec);
// This is the updated "some_vec": [1, 3, 4, 5, 5]
}
FnOnce
:(我在Fn
示例中仅删除了闭包内部的"some_vec"前面的"&")
fn main() {
let some_vec = vec![1, 3, 4];
let get_that_same_vec = || { // "get_that_same_vec" type: impl FnOnce() -> Vec<i32>
some_vec
// as you can see the closure is specified to implement the *FnOnce* trait,
// rust-analyzer shows only the most relevant trait that a closure implements
// meaning that, in this case, a closure is marked as such that can only be called once,
// since it passes the ownership of the data it captures to another entity.
// In this case, that entity is the "get_that_same_vec" variable.
};
println!("This is the vec: {:?}", get_that_same_vec());
// the call to println below does not compile and throws error "value used here after move",
// and the way the compiler is able to infer this is by knowing
// that a closure that implements only the `FnOnce` trait and no other trait
// can only be called once, it no longer holds the ownership of a value it moved the ownership of the first time it was called.
println!("This is the vec: {:?}", get_that_same_vec()); // this does not compile
}
这是针对 @huon 和 @svitanok 答案的简历,强调了 Fn
和 FnMut
(以及其他类型)确实扩展了 FnOnce
,但它们是分开使用的:
fn main() {
let f: Box<dyn Fn()> = Box::new(|| { println!("foo"); });
f();
f();
let mut f: Box<dyn FnMut()> = Box::new(|| { println!("foo"); });
f();
f();
let f: Box<dyn FnOnce()> = Box::new(|| { println!("foo"); });
f();
f(); // compile error!
}