😊
Rustでどんな値型も格納できるHashMapを実装する
std::any::Any
を使ってどんな値も格納できるHashMapを実装する方法をまとめます。
実現方法の要点としては以下。
-
HashMap
の値型にBox<dyn Any>
もしくは&'a dyn Any
を指定する-
Box<dyn Any>
の場合は値はヒープに格納され、&'a dyn Any
の場合は値のライフタイムに依存します。
-
- 型パラメータに
std::any::Any
制約を付ける
Box<dyn Any>
版
Box
版の実装コードは以下です。
pub struct Config {
values: HashMap<String, Box<dyn Any>>,
}
impl Config {
pub fn new() -> Self {
Self {
values: HashMap::new(),
}
}
pub fn set<T>(&mut self, k: String, v: T)
where
T: Any,
{
self.values.insert(k, Box::new(v));
}
pub fn get<T>(&self, key: String) -> Option<&T>
where
T: Any,
{
self.values.get(&key).and_then(|v| v.downcast_ref::<T>())
}
}
使い方。
let mut config = Config::new();
let key = "aaa".to_string();
let value = "bbb".to_string()
config.set(key.clone(), value);
let s = config.get::<String>(key);
println!("result = {:?}", s);
&'a dyn Any
版
Box
を使わない場合の実装コードは以下です。
pub struct Config<'a> {
values: HashMap<String, &'a dyn Any>,
}
impl<'a> Config<'a> {
pub fn new() -> Self {
Self {
values: HashMap::new(),
}
}
pub fn set<T>(&mut self, k: String, v: &'a T)
where
T: Any,
{
self.values.insert(k, v);
}
pub fn get<T>(&self, key: String) -> Option<&T>
where
T: Any,
{
self.values.get(&key).and_then(|&v| v.downcast_ref::<T>())
}
}
使い方
let mut config = Config::new();
let key = "aaa".to_string();
let value = "bbb".to_string();
config.set(key.clone(), &value);
let s = config.get::<String>(key);
println!("result = {:?}", s);
とても簡単!
参考リンク
Discussion