临时值的正确函数类型

Correct Function Type for temporary value

提问人:Test 提问时间:9/22/2022 最后编辑:HerohtarTest 更新时间:9/27/2022 访问量:51

问:

在函数内部调用的“回调”函数的正确函数类型是什么?

fn or_else(value: u32, f: ???) -> u32 {
    if (value == 0) {
        f()
    } else {
        value
    }
}

用法示例:

or_else(0, || { 3 })

我使用时生锈是怎么回事?f: &dyn FnOnce() -> u32

错误:

cannot move a value of type dyn FnOnce() -> u32: the size of dyn FnOnce() -> u32 cannot be statically determinedrustcE0161
cannot move out of `*f` which is behind a shared reference
move occurs because `*f` has type `dyn FnOnce() -> u32`, which does not implement the `Copy` trait

我无法理解 E0161。

Rust 回调 闭包

评论

0赞 PiRocks 9/22/2022
这是因为 FnOnce 需要闭包的所有权才能调用它,而 Fn() 只需要一个引用,而 FnMut 需要一个可变引用。
0赞 Test 9/22/2022
1. 如果知道闭包只会调用一次,应该使用哪种类型?2. 你能说说为什么在这种情况下它没有所有权吗?FnOnce如何“拥有”关闭的所有权?FnOnce 和闭包不是一回事吗?
0赞 Chayim Friedman 9/22/2022
根据回退函数的热度,以及它是否真的需要 over 的特殊功能,我会说 或 .FnOnceFnMut&mut dyn FnMut()impl FnOnce()

答:

3赞 Kevin Reid 9/22/2022 #1

在本例中,接受函数的最一般方法是使用以下任一语法使函数泛型

fn or_else(value: u32, f: impl FnOnce() -> u32) -> u32 {
fn or_else<F: FnOnce() -> u32>(value: u32, f: F) -> u32 {

这就是说:可以是调用方愿意提供的任何类型,只要该类型实现(是一个可以调用一次的函数)。fFnOnce

当我使用 f: 时,生锈生气是什么?&dyn FnOnce() -> u32

FnOnce以它只能调用一次的想法命名,但它的实际意思是通过调用函数值来消耗(移动)。因此,一旦你调用了这个函数,你就不再拥有它了。

但是,如果你有,那么你就不能移动这个值,因为你不拥有它。因此,不可能通过引用来调用。(同样,a 需要可变引用,并且不能使用不可引用来调用。&FFFnOnceFnMut

所以,这个类型是无用的——它可以存在,但它永远不能被调用。如果你想使用(这可能是一个合理的选择),那么你必须使用 or .&dyn FnOncedyn&dyn Fn&mut dyn FnMut

但是,对于接受回调的通用函数,通常最好使用泛型而不是 .这是因为:dyn

  • 它允许你接受,最一般的功能特征FnOnce
  • 它允许通过值引用传递函数,如果对于特定函数来说是可能的,因为对 / 函数的引用也实现 / 本身FnFnMutFnFnMut
  • 它允许编译器内联回调函数,以便代码可以作为一个整体进行优化