【发布时间】:2015-01-12 16:50:41
【问题描述】:
我正在尝试将闭包存储为 HashMap 值。如果我按值传递闭包 arg,一切正常:
use std::collections::hash_map::HashMap;
fn main() {
let mut cmds: HashMap<String, Box<FnMut(String)->()>>
= HashMap::new();
cmds.insert("ping".to_string(), Box::new(|&mut:s| { println!("{}", s); }));
match cmds.get_mut("ping") {
Some(f) => f("pong".to_string()),
_ => ()
}
}
(playpen)
但如果我想要一个带有引用 arg 的闭包,事情就往南了:
use std::collections::hash_map::HashMap;
fn main() {
let mut cmds: HashMap<String, Box<FnMut(&str)->()>>
= HashMap::new();
cmds.insert("ping".to_string(), Box::new(|&mut:s| { println!("{}", s); }));
match cmds.get_mut("ping") {
Some(f) => f("pong"),
_ => ()
}
}
<anon>:8:37: 8:78 error: type mismatch: the type `closure[<anon>:8:46: 8:77]` implements the trait `core::ops::FnMut(_)`, but the trait `for<'r> core::ops::FnMut(&'r str)` is required (expected concrete lifetime, found bound lifetime parameter )
<anon>:8 cmds.insert("ping".to_string(), Box::new(|&mut:s| { println!("{}", s); }));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:8:37: 8:78 note: required for the cast to the object type `for<'r> core::ops::FnMut(&'r str)`
<anon>:8 cmds.insert("ping".to_string(), Box::new(|&mut:s| { println!("{}", s); }));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
(playpen)
我阅读了How to rewrite code to new unboxed closures 的答案,并尝试将地图构建分解为自己的功能,以便有一个地方挂where 子句,但没有骰子:
use std::collections::hash_map::HashMap;
fn mk_map<F>() -> HashMap<String, (String, Box<F>)>
where F: for<'a> FnMut(&'a str) -> ()
{
let mut cmds: HashMap<String, (String, Box<F>)> = HashMap::new();
cmds.insert("ping".to_string(), ("ping".to_string(), Box::new(|&mut:s| { println!("{}", s); })));
cmds
}
fn main() {
let cmds = mk_map();
match cmds.get_mut("ping") {
Some(&mut (_, ref mut f)) => f("pong"),
_ => println!("invalid command")
}
}
<anon>:8:58: 8:99 error: mismatched types: expected `Box<F>`, found `Box<closure[<anon>:8:67: 8:98]>` (expected type parameter, found closure)
<anon>:8 cmds.insert("ping".to_string(), ("ping".to_string(), Box::new(|&mut:s| { println!("{}", s); })));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(playpen)
这样做的正确方法是什么?
【问题讨论】: