Type signature of a Rust HashMap of a function

后端 未结 2 1710
时光说笑
时光说笑 2021-01-27 21:41

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

2条回答
  •  深忆病人
    2021-01-27 22:29

    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) -> Expression {plus}, and is actually a Voldemort Type: it cannot be named.

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

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

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


    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();
    

提交回复
热议问题