I create a HashMap which maps strings to functions of type Vec
, where Expression
is a type I have defined. The code
If you look closely at the difference you will have your answer, although it can be puzzling.
I expect that plus
has been declared as:
fn plus(v: Vec) -> Expression;
In this case, the type of plus
is fn(Vec
, and is actually a Voldemort Type: it cannot be named.
Most notably, it differs from an eventual fn(Vec
.
Those two types can be coerced into a bare fn(Vec
(without the {plus}
/{multiply}
denomination).
And this latter type can be transformed into a Fn(Vec
, which is a trait for any callable which do not modify their environments (such as the closure |v: Vec
).
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}
is a zero-sized type,fn(a) -> b
is a pointer to function,Box 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) -> 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;
let functions: HashMap<_, _> =
vec!(("+", plus as FnExpr)).into_iter().collect();