types - 函数的 Rust HashMap 的类型签名

标签 types compiler-errors rust

我创建了一个 HashMap,它将字符串映射到 Vec<Expression> -> Expression 类型的函数, 其中Expression是我定义的类型。有问题的代码是:

let functions: HashMap<_, _> = vec!(("+", Box::new(plus))).into_iter().collect();

如果我让 Rust 为我推断类型,如上面的代码所示,它会编译并运行良好,如上面的代码所示。但是,如果我尝试指定类型,它不会编译:

let functions: HashMap<&str, Box<Fn(Vec<Expression>) -> Expression>> =
    vec!(("+", Box::new(plus))).into_iter().collect();

编译器错误消息不是很有帮助:

let functions: HashMap<&str, Box<Fn(Vec<Expression>) -> Expression>> = vec!(("+", Box::new(plus))).into_iter().collect();
^^^^^^^ a collection of type `std::collections::HashMap<&str, std::boxed::Box<std::ops::Fn(std::vec::Vec<Expression>) -> Expression>>` cannot be built from an iterator over elements of type `(&str, std::boxed::Box<fn(std::vec::Vec<Expression>) -> Expression {plus}>)`

这个 HashMap 的实际类型是什么? ?

最佳答案

如果您仔细观察差异,您就会找到答案,尽管这可能令人费解。

我希望 plus已声明为:

fn plus(v: Vec<Expression>) -> Expression;

在这种情况下,plus 的类型是fn(Vec<Expression>) -> Expression {plus} , 实际上是一个 Voldemort Type : 无法命名。

最值得注意的是,它不同于最终的 fn(Vec<Expression>) -> Expression {multiply} .

这两种类型可以强制转换成一个空的 fn(Vec<Expression>) -> Expression (没有 {plus}/{multiply} 面额)。

后一种类型可以转换为 Fn(Vec<Expression>) -> Expression ,这是任何不修改其环境的可调用对象的特征(例如闭包 |v: Vec<Expression>| v[0].clone())。


然而,问题在于,虽然 fn(a) -> b {plus}可以转化为fn(a) -> b可以转化为Fn(a) -> b ...转换需要改变内存表示。这是因为:

  • fn(a) -> b {plus}是零大小的类型,
  • fn(a) -> b是指向函数的指针,
  • Box<Fn(a) -> b>是一个装箱的 trait 对象,通常表示虚拟指针数据指针。

因此类型归属不起作用,因为它只能执行无成本的强制转换。


解决方案是在为时已晚之前执行转换:

// Not strictly necessary, but it does make code shorter.
type FnExpr = Box<Fn(Vec<Expression>) -> Expression>;

let functions: HashMap<_, _> =
    vec!(("+", Box::new(plus) as FnExpr)).into_iter().collect();
               ^~~~~~~~~~~~~~~~~~~~~~~~

或者您可能更愿意保留未装箱的函数:

// Simple functions only
type FnExpr = fn(Vec<Expression>) -> Expression;

let functions: HashMap<_, _> =
    vec!(("+", plus as FnExpr)).into_iter().collect();

关于types - 函数的 Rust HashMap 的类型签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45159414/

相关文章:

rust - 如何在 src 中布局我的 Rust 模块以跨我的应用程序访问

c# - 如何从字符串表示中获取泛型类型?

python - 获取给定值对应的 "zero value"

c - 使用 Embeddable Common Lisp 编译文件的正确方法是什么?

visual-studio-2008 - 从VS2008 Prof迁移到VC++ Express 2008时出现构建问题

rust - 将整个宏输入传递给另一个宏

types - GraphQL - 将枚举值作为参数直接传递给突变?

typescript - typescript 中的条件类型

java - 如何防止对象自动转换为字符串

c++ - 将 Cpp 转换为 Rust,处理全局静态对象