本文介绍了函数的Rust HashMap的类型签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I create a HashMap which maps strings to functions of type Vec<Expression> -> Expression, where Expression is a type I have defined. The code in question is:

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

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

If I let Rust infer the type for me, as in the code above, it compiles and runs fine, as in the code above. However, if I try to specify the type, it doesn't compile:

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

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

The compiler error message isn't very helpful:

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的实际类型是什么

推荐答案

如果仔细研究一下差异,尽管会令人困惑,但您会得到答案。

If you look closely at the difference you will have your answer, although it can be puzzling.

我希望 plus 被声明为:

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

在这种情况下,加的类型是 fn(Vec< Expression>)->表达式{plus} ,实际上是:它不能是

In this case, the type of plus is fn(Vec<Expression>) -> Expression {plus}, and is actually a Voldemort Type: it cannot be named.

最值得注意的是,它与最终的 fn(Vec< Expression>)->不同。表达式{multiply} 。

Most notably, it differs from an eventual fn(Vec<Expression>) -> Expression {multiply}.

这两种类型可被强制转换为裸 fn(Vec< Expression>)- >表达式(不包括 {plus} / {multiply} 面额)。

Those two types can be coerced into a bare fn(Vec<Expression>) -> Expression (without the {plus}/{multiply} denomination).

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

And this latter type can be transformed into a Fn(Vec<Expression>) -> Expression, which is a trait for any callable which do not modify their environments (such as the closure |v: Vec<Expression>| v[0].clone()).

但是问题是,当 fn( a)-> b {plus} 可以转换为 fn(a)-> b 可以转换为 Fn(a)-> b ...转换需要更改内存表示形式。这是因为:

The problem, however, is that while fn(a) -> b {plus} can be transformed into fn(a) -> b which can be transformed into Fn(a) -> b... the transformation requires a change of memory representation. This is because:


  • fn(a)-> b {plus} 是零大小的类型,

  • fn(a)-> b 是函数的指针,

  • Box< Fn(a)-> b> 是一个装箱的特征对象,通常表示虚拟指针数据指针。

  • fn(a) -> b {plus} is a zero-sized type,
  • fn(a) -> b is a pointer to function,
  • Box<Fn(a) -> b> is a boxed trait object which generally means both a virtual pointer and a data pointer.

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

And therefore the type ascription doesn't work, because it can only perform cost-free coercions.

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

The solution is to perform the transformation before it's too late:

// 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();
               ^~~~~~~~~~~~~~~~~~~~~~~~

或者也许您宁愿保留未装箱的功能:

Or maybe you'd rather keep unboxed functions:

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

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

这篇关于函数的Rust HashMap的类型签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 20:46