如何在数组中存储函数指针?

16

你如何将函数(或函数指针)放入数组中以进行测试?

fn foo() -> isize { 1 }
fn bar() -> isize { 2 }

fn main() {
    let functions = vec![foo, bar];
    println!("foo() = {}, bar() = {}", functions[0](), functions[1]());
}

这段代码位于Rust playground(Rust游乐场)中。

这是我得到的错误代码:

error: mismatched types:
 expected `fn() -> isize {foo}`,
    found `fn() -> isize {bar}`
(expected fn item,
    found a different fn item) [E0308]

    let functions = vec![foo, bar];
                              ^~~

Rust将我的函数(值)视为不同的类型,尽管它们具有相同的签名,这让我感到惊讶。


有趣的是,这只是 vec![] 的限制(实际上,这是使用 box [...] 时的问题)。您可以轻松地创建一个函数指针的数组或切片:let arr = [foo, bar] - Lukas Kalbertodt
1个回答

18

最近,每个函数被赋予了自己独特的类型,原因我不记得了。重要的是你需要给编译器一个提示(注意在functions上的类型):

fn foo() -> isize {
    1
}
fn bar() -> isize {
    2
}
fn main() {
    let functions: Vec<fn() -> isize> = vec![foo, bar];
    println!("foo() = {}, bar() = {}", functions[0](), functions[1]());
}

你也可以这样做:

let functions = vec![foo as fn() -> isize, bar];

谢谢!看到使用案例变得更加困难总是令人遗憾;我希望他们有一些理由来解释这个破坏性的变化。在左侧注释类型并不那么糟糕,只要你知道如何编写函数类型签名,而我还没有掌握这个技能。 - Andrew Wagner
"fn items"有一个好处:它避免了通过虚函数调用函数指针的调用。LLVM可能会在优化过程中去虚拟化该调用,但是fn item和非盒式闭包调用应始终是直接的,而不依赖于优化器的正确性。 - bluss
你可以将它们放在一个数组中,但是你需要进行一些类型转换:let functions = [foo as fn() -> isize, bar as fn() -> isize]; 或者 let functions: [fn() -> isize; 2] = [foo, bar];。你也可以创建一个切片 let functions: &[fn() -> isize] = &[foo, bar]; - Shepmaster
我希望我可以给这个多次点赞。如果语言中没有继承,我完全忘记了它可能会推断出过于具体的类型,并需要收敛。在这上面花费了几个沮丧的小时... - Richard Rast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接