为什么用`box`语法装入一个函数指针数组只能用一个临时的`let`绑定?

Luk*_*odt 6 rust

我有两个虚函数:

fn foo() -> u32 { 3 }
fn bar() -> u32 { 7 }
Run Code Online (Sandbox Code Playgroud)

我想创建一个盒装的函数指针切片:Box<[fn() -> u32]>.我想用box语法来做(我知道它不是两个元素所必需的,但我的实际用例是不同的).

我尝试了几件事(游乐场):

// Version A
let b = box [foo, bar] as Box<[_]>;

// Version B
let tmp = [foo, bar];
let b = box tmp as Box<[_]>;

// Version C
let b = Box::new([foo, bar]) as Box<[_]>;
Run Code Online (Sandbox Code Playgroud)

版本B和C工作正常(C虽然不会对我有用Box::new),但版本A错误:

error[E0605]: non-primitive cast: `std::boxed::Box<[fn() -> u32; 2]>` as `std::boxed::Box<[fn() -> u32 {foo}]>`
 --> src/main.rs:8:13
  |
8 |     let b = box [foo, bar] as Box<[_]>;
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
Run Code Online (Sandbox Code Playgroud)

显然,由于某种原因,在版本A中,编译器无法强制函数项来运行指针.这是为什么?为什么它与额外的临时let绑定一起使用?


这个问题的灵感来自另一个问题.我想知道为什么vec![foo, bar]错误,但[foo, bar]工作正常.我看了一下定义,vec![]发现这部分让我很困惑.

Sve*_*ach 4

对我来说,这看起来像是类型推断算法的一个特质,除了当前的推断算法碰巧表现得像它那样之外,可能没有更深层的原因。没有关于类型推断何时起作用、何时不起作用的正式规范。如果遇到类型推断引擎无法处理的情况,则需要添加类型注释,或者以编译器可以正确推断类型的方式重写代码,而这正是您需要在此处执行的操作。

\n\n

Rust中的每个函数都有自己单独的函数项类型,它不能直接通过语法命名,而是fn() -> u32 {foo}在错误消息中显示为例如。有一种特殊的强制转换,如果具有相同签名的函数项类型出现在 a 的不同臂match、 an 的不同分支if或数组的不同元素中,则将它们转换为相应的函数指针类型。这种强制转换与其他强制转换不同,因为它不仅发生在显式类型化的上下文(“强制转换站点”)中,而且这种特殊处理可能是造成这种特性的原因。

\n\n

特殊强制是由绑定触发的

\n\n
let tmp = [foo, bar];\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以 的类型tmp完全确定为[fn() -> u32; 2]。然而,在编写时,类型推断算法中似乎没有足够早地触发特殊强制

\n\n
let b = box [foo, bar] as Box<[_]>;\n
Run Code Online (Sandbox Code Playgroud)\n\n

编译器首先假设数组的项类型是其第一个元素的类型,显然当试图确定_此处表示什么时,编译器仍然没有根据错误消息更新这个概念 \xe2\x80\x93,这里的_意思是推断fn() -> u32 {foo}。有趣的是,编译器在打印错误消息时已经正确推断出 的完整类型box [foo, bar],因此行为确实相当奇怪。只有详细查看编译器源代码才能给出完整的解释。

\n\n

Rust 的类型求解器引擎通常无法处理理论上应该能够解决的情况。Niko Matsakis 的chalk 引擎旨在在未来的某个时刻为所有这些情况提供通用解决方案,但我不知道该项目的状态和时间表是什么。

\n