rust - 使用函数指针时为 "Expected fn item, found a different fn item"

标签 rust

我有以下代码(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 项?

最佳答案

函数项与函数指针

当您通过名称引用函数时,您获得的类型不是函数指针(例如 fn(u32) -> bool)。相反,您会得到函数的 item 类型 的零大小值(例如 fn(u32) -> bool {foo})。

该值的大小为零,因为它不存储实际的函数指针。类型完美地标识了函数,因此无需在类型中存储实际数据。这有几个优点,主要是关于更容易优化。函数指针就像您对其他语言的期望一样:它存储函数的地址。

函数指针通过存储的地址指向函数; 功能项通过类型信息引用功能。

在许多情况下,函数项可以强制转换为函数指针,例如:作为函数的参数和在 let _: fn(u32) -> bool = foo; 语句中。此外,您可以将函数项显式转换为函数指针:foo as fn(u32) -> bool

您可以在 function items 上的引用资料中阅读有关此主题的更多信息, function pointerscoercion .



解决你的问题

在您的情况下,编译器不够聪明,无法确定您想要 foobar 中的函数指针而不是函数项。当您调用 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;

通常:在某处指定函数指针类型以触发强制转换会起作用

关于rust - 使用函数指针时为 "Expected fn item, found a different fn item",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39070143/

相关文章:

hash - 为什么 hash() 和 hasher.write() 的结果不一样?

SslStream<TcpStream> 读取不返回客户端的消息

rust - 火箭内的 Handlebars helper

json - Rust使用Postgres JSON属性: cannot convert between the Rust type `alloc::string::String` and the Postgres type `jsonb`

使用特征对象时,使用rust 具有特征绑定(bind)的泛型类型

generics - 当需要特征 Seek 时,如何将 Vec<T> 传递给函数?

rust - 如何在 Rust 的可变方法中为结构体字段设置新值并返回旧值

rust - 有没有办法在 Rust 中删除静态生命周期对象?

multithreading - 在 Rayon 线程内调用 `Arc::new()` 会导致垃圾编译器错误

rust - pub(crate)函数声明语法是什么意思?什么时候使用? [复制]