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
}
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:
(all我在这里做的是:在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
}
3条答案
按热度按时间t3psigkw1#
每个traits都代表了关于闭包/函数的越来越多的限制性属性,由它们的
call_...
方法的签名表示,特别是self
的类型:FnOnce
(self
)是可以调用一次的函数FnMut
(&mut self
)是可以在&mut
环境中调用的函数Fn
(&self
)是只有对环境具有&
访问权限时才能调用的函数闭包
|...| ...
将自动实现尽可能多的那些。FnOnce
:一个不能被调用一次的闭包就不配称为闭包。注意,如果一个闭包只实现了FnOnce
,那么它只能被调用一次。FnMut
,允许它们被多次调用(如果对函数对象有无别名访问)。Fn
,允许它们在任何地方被调用。这些限制直接来自
self
的类型和闭包到结构体中的“去糖”;在我的博客文章Finding Closure in Rust中描述。有关闭包的信息,请参阅 The Rust Programming Language 中的Closures: Anonymous Functions that Can Capture Their Environment。
wgx48brx2#
看到现在这里只有一个其他的答案,可能不会让一些人完全清楚问题的内容,因为它没有为我,我将提供一些例子和一些推理,帮助我理解这些闭包特性是什么:
Fn
:FnMut
:Fn
trait所指示的。如手术记录:“改变闭包体的状态会使编译器无法在其上实现Fn
。”)FnOnce
:什么时候一个闭包只实现这个trait而不实现其他trait?“:当它将捕获值的所有权移出其作用域时,因为其他两个trait,根据它们的定义,如果它将捕获值的所有权移出其作用域,则不会由闭包实现。
(All这些traits只是编译器确定在哪里可以允许使用任意闭包的一种方式,同时保持闭包操作的数据的内存处于“安全”状态)
(note:我不能用“impl”类型注解“updated_vec”let绑定,所以我将在绑定定义附近的注解中指定一个由rust-analyzer推断的类型)
Fn
特性:字符串
FnMut
:(On为什么我们需要用“mut”标记持有
FnMut
闭包的变量(参见this great answer)型
FnOnce
:(all我在这里做的是:在
Fn
示例中,我删除了闭包内部“some_vec”前面的“&”)型
q43xntqr3#
以下是@huon和@svitanok的回复,强调
Fn
和FnMut
(以及其他类型)确实扩展了FnOnce
,但它们是分开使用的:字符串