函数的Rust HashMap的类型签名
我创建了一个HashMap,它将字符串映射到类型为Vec<Expression> -> Expression
的函数,其中Expression
是我定义的类型。有问题的代码是:函数的Rust HashMap的类型签名
let functions: HashMap<_, _> = vec!(("+", Box::new(plus))).into_iter().collect();
如果我让拉斯特推断类型对我来说,在上面的代码,它编译并运行正常,因为在上面的代码。但是,如果我尝试指定类型,它不会编译:
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>
被装箱性状对象这通常意味着两个虚拟指针和一个数据指针。
因此,类型归属不起作用,因为它只能执行无成本的强制。
的解决方案是执行转换为时已晚之前:
// 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();
顺便说一句,'FN(A) - > B {加}'是不是指针[它是零大小。](https://play.rust-lang.org/?gist=0ad4ee6d789294e3af47d0a71dc74940&version=stable) – red75prime
@ red75prime:哦,对,我总是忘记这件整洁的东西! –
感谢您的详细和全面的答案这完全回答了我的问题。 – isaacg
错误消息的相关部分Box<std::ops::Fn ... >
和Box<fn ... {plus}>
。首先是盒装Fn
特质对象。第二个是盒装功能plus
。请注意,它不是指向函数的方块指针,它将是Box<fn ...>
而没有{plus}
部分。它是功能plus
本身的独特和不可名字的类型。
那就是你不能写这个HashMap
的实际类型,因为它包含的类型是不可命名的。这不是什么大不了的,你只能把plus
函数加入它。
下面的代码提供编译错误
let functions: HashMap<_, _> =
vec![("+", Box::new(plus)),
("-", Box::new(minus))].into_iter().collect();
^^^^^ expected fn item, found a different fn item
这工作,但它是无用
let functions: HashMap<_, _> =
vec![("+", Box::new(plus)),
("-", Box::new(plus))].into_iter().collect();
一种可能的解决方案是将一个向量的第一元素转换成所需要的类型。
type BoxedFn = Box<Fn(Vec<Expression>) -> Expression>;
let functions: HashMap<&str, BoxedFn> =
vec![("+", Box::new(plus) as BoxedFn),
("_", Box::new(minus))].into_iter().collect();
另一个是中间变量的类型归属。
type BoxedFn = Box<Fn(Vec<Expression>) -> Expression>;
let v: Vec<(_, BoxedFn)> = vec![("+", Box::new(plus)), ("_", Box::new(minus))];
let functions: HashMap<&str, BoxedFn> = v.into_iter().collect();
看来我的谷歌福是真的很弱,我敢发誓,有这种重复:( –