我创建了一个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的实际类型是什么?
发布于 2017-07-18 07:30:37
如果你仔细观察差异,你会得到你的答案,虽然这可能是令人费解的。
我希望plus被宣布为:
fn plus(v: Vec<Expression>) -> Expression;在本例中,plus的类型是fn(Vec<Expression>) -> Expression {plus},实际上是一个伏地魔型:它不能命名。
最值得注意的是,它不同于最终的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();发布于 2017-07-18 07:32:47
错误消息的相关部分是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();https://stackoverflow.com/questions/45159414
复制相似问题