Storing an unboxed closure with a reference arg in a HashMap

感情迁移 提交于 2019-12-06 12:16:28

My solution:

#![allow(unstable)]
use std::collections::hash_map::HashMap;

// #1 returning a trait object   
fn mk_map<'a>() -> HashMap<String, (String, Box<FnMut(&str) + 'a>)> {
    let mut cmds : HashMap<_, (_, Box<FnMut(&str)>)> = HashMap::new();

    cmds.insert("ping".to_string(), ("ping".to_string(), 
        Box::new(|&mut: s: &str| { println!("{}", s); })));
    // #2                  ^-- give a little help to the compiler here
    cmds
}   

fn main() {
    let mut cmds = mk_map();
    // minor change: cmds needs to be mutable
    match cmds.get_mut("ping") {
        Some(&mut (_, ref mut f)) => f("pong"),
        _ => println!("invalid command")
    }
}

Ingredients:

  1. return a trait object
  2. give some help to the compiler on the type of the closure's parameter: Box::new(|&mut: s: &str|

To be honest, I'm not 100% sure about the reason for #2 (I mean, at least leaving it out should give a more intelligible error message). Probably an issue with rustc.

On #1, I'm almost sure it's required because you can't name a concrete return type for a closure returned from a function (it's an anonymous type created on the fly by the compiler), so Trait objects for now should be the only way to return a closure.

Appendix responding to comment:

imagine you have a trait Foo {} implemented by a few types:

trait Foo {}
impl Foo for u32 {}
impl Foo for Vec<f32> {}

if you write a function like you did with mk_map (let's call it make_foo) I commented that it's going to be hard to implement it. Let's see:

fn mk_foo<F>() -> Box<F> where F: Foo {
    unimplemented!()
}

the signature of mk_foo says that I should be able to call the function with any type that implements Foo. So this should all be valid:

   let a: Box<Vec<f32>> = mk_foo::<Vec<f32>>();
   let b: Box<u32> = mk_foo::<u32>();

i.e. the function, as written, is not returning a trait object. It's promising to return a Box with any concrete type the caller chooses. That's why it's not easy to actually implement the function. It should know how to create several types from nothing.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!