我有两个虚函数:
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![]
发现这部分让我很困惑.
对我来说,这看起来像是类型推断算法的一个特质,除了当前的推断算法碰巧表现得像它那样之外,可能没有更深层的原因。没有关于类型推断何时起作用、何时不起作用的正式规范。如果遇到类型推断引擎无法处理的情况,则需要添加类型注释,或者以编译器可以正确推断类型的方式重写代码,而这正是您需要在此处执行的操作。
\n\nRust中的每个函数都有自己单独的函数项类型,它不能直接通过语法命名,而是fn() -> u32 {foo}
在错误消息中显示为例如。有一种特殊的强制转换,如果具有相同签名的函数项类型出现在 a 的不同臂match
、 an 的不同分支if
或数组的不同元素中,则将它们转换为相应的函数指针类型。这种强制转换与其他强制转换不同,因为它不仅发生在显式类型化的上下文(“强制转换站点”)中,而且这种特殊处理可能是造成这种特性的原因。
特殊强制是由绑定触发的
\n\nlet tmp = [foo, bar];\n
Run Code Online (Sandbox Code Playgroud)\n\n所以 的类型tmp
完全确定为[fn() -> u32; 2]
。然而,在编写时,类型推断算法中似乎没有足够早地触发特殊强制
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]
,因此行为确实相当奇怪。只有详细查看编译器源代码才能给出完整的解释。
Rust 的类型求解器引擎通常无法处理理论上应该能够解决的情况。Niko Matsakis 的chalk 引擎旨在在未来的某个时刻为所有这些情况提供通用解决方案,但我不知道该项目的状态和时间表是什么。
\n