“预期FN项目,发现了一个不同的FN项目”与函数指针工作时

问题描述 投票:8回答:2

我有以下代码(Playground):

// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
    x % 2 == 0
}
fn bar(x: u32) -> bool {
    x == 27
}


fn call_both<F>(a: F, b: F)
where
    F: Fn(u32) -> bool,
{
    a(5);
    b(5);
}

fn main() {
    call_both(foo, bar);  // <-- error
}

对我来说,好像这应该编译为foobar具有相同的签名:fn(u32) -> bool。然而,我得到以下错误:

error[E0308]: mismatched types
  --> src/main.rs:20:20
   |
20 |     call_both(foo, bar);
   |                    ^^^ expected fn item, found a different fn item
   |
   = note: expected type `fn(u32) -> bool {foo}`
              found type `fn(u32) -> bool {bar}`

同样的错误可以使用此代码被触发:

let mut x = foo;
x = bar;  // <-- error

我也试着投bar再次函数指针类型:

let mut x = foo;
x = bar as fn(u32) -> bool;  // <-- error

这就产生了一个稍微不同的错误:

error[E0308]: mismatched types
  --> src/main.rs:20:9
   |
20 |     x = bar as fn(u32) -> bool;
   |         ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
   |
   = note: expected type `fn(u32) -> bool {foo}`
              found type `fn(u32) -> bool`

我一点都看不懂这些错误。什么是FN项目与FN指针和为什么foobar不同FN项目?

rust
2个回答
11
投票

每个命名的函数有一个独特的类型,因为Rust PR #19891被合并。你可以,但是,投职能,相应的函数指针类型与as运营商。

call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);

这也是有效的只有先拿的功能:投将在第二推断,因为这两个功能必须有相同的类型。

call_both(foo as fn(u32) -> bool, bar);

4
投票

Function item vs. function pointer

当你用它的名字是指一个功能,你得到的类型不是一个函数指针(例如fn(u32) -> bool)。相反,你得到的功能的项目类型的零大小的值(例如fn(u32) -> bool {foo})。

该值是零大小,因为它没有存储实际的函数指针。该型完美识别功能,所以没有必要存储在类型的实际数据。这样做有几个好处,主要是对容易优化。一个函数指针像你一样会从其他语言的期待:它的地址保存到该函数。

一个函数指针指经由存储的地址的功能;一个功能项指的是经由类型信息的功能。

甲功能项可被强制转换为一个函数指针在许多情况下,例如:作为参数的函数,并且在let _: fn(u32) -> bool = foo;语句。此外,还可以显式转换功能项目函数指针:foo as fn(u32) -> bool

你可以阅读更多关于这个话题在function itemsfunction pointerscoercion参考。


Solution to your problem

在你的情况,编译器是不是足够聪明弄清楚,你想从你foobar而不是功能项的函数指针。当你调用call_both(foo, bar)则编译器将泛型类型Ffn(u32) -> bool {foo},因为这是第一个参数的类型。然后抱怨说,第二个参数不具有相同的类型。

您可以修复,通过明确指定F参数:

call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar);       // <-- even this works

指定类型之后,编译器可以正确地迫使所述参数的函数的指针。你也可以as铸明确fn(u32) -> bool的第一个参数。

您可以通过显式声明函数指针类型解决您的第二个例子,太:

let mut x: fn(u32) -> bool = foo;
x = bar;

一般来说:某处指定的函数指针类型触发强制将工作。

© www.soinside.com 2019 - 2024. All rights reserved.