我有以下代码(游乐场):
// 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
}
对我来说,它看起来这应该是编译foo和bar具有相同的签名: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指针以及为什么foo和bar不同的fn项目?
Luk*_*odt 14
当您通过名称引用函数时,您获得的类型不是函数指针(例如fn(u32) -> bool)。相反,您会得到函数项类型(例如fn(u32) -> bool {foo})的零大小值。
该值为零大小,因为它不存储实际的函数指针。类型完美地标识了函数,因此不需要在类型中存储实际数据。这有几个优点,主要是关于更容易优化。函数指针就像您对其他语言所期望的那样:它存储函数的地址。
甲函数指针指经由存储的地址的功能; 一个功能项指的是经由类型信息的功能。
在许多情况下,可以将函数项强制转换为函数指针,例如:作为函数的参数和 inlet _: fn(u32) -> bool = foo;语句。此外,您可以显式地将函数项转换为函数指针:foo as fn(u32) -> bool。
您可以在关于函数项、函数指针和强制的参考资料中阅读有关此主题的更多信息。
在您的情况下,编译器不够聪明,无法确定您想要函数指针来自fooandbar而不是函数项。当您调用call_both(foo, bar)编译器时,将泛型类型F设置为fn(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;
通常:在某处指定函数指针类型以触发强制转换将起作用。
Fra*_*gné 12
自从Rust PR#19891合并以来,每个命名函数都有一个不同的类型.但是,您可以使用as运算符将函数转换为相应的函数指针类型.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
仅转换第一个函数也是有效的:在第二个函数中将推断转换,因为两个函数必须具有相同的类型.
call_both(foo as fn(u32) -> bool, bar);
| 归档时间: | 
 | 
| 查看次数: | 990 次 | 
| 最近记录: |