出于解释性编程语言的习惯,我想根据键修改许多值。我假设我将所有信息存储在为该项目准备的结构中。所以我开始迭代:
struct Container {
x: String,
y: String,
z: String
}
impl Container {
// (...)
fn load_data(&self, data: &HashMap<String, String>) {
let valid_keys = vec_of_strings![ // It's simple vector with Strings
"x", "y", "z"
] ;
for key_name in &valid_keys {
if data.contains_key(key_name) {
self[key_name] = Some(data.get(key_name);
// It's invalid of course but
// I do not know how to write it correctly.
// For example, in PHP I would write it like this:
// $this[$key_name] = $data[$key_name];
}
}
}
// (...)
}
也许是宏?我试着用它们。 key_name
始终被解释为原样,我无法获得key_name
的价值。
如何在不重复每个值的代码的情况下执行此操作?
答案 0 :(得分:3)
使用宏,我总是提倡从直接代码开始,然后看看有什么重复。在这种情况下,我们从
开始fn load_data(&mut self, data: &HashMap<String, String>) {
if let Some(v) = data.get("x") {
self.x = v.clone();
}
if let Some(v) = data.get("y") {
self.y = v.clone();
}
if let Some(v) = data.get("z") {
self.z = v.clone();
}
}
请注意差异的数量:
&mut self
。Option
中存储String
。一旦你的代码工作,你就可以看到如何抽象。 始终首先尝试使用&#34; light&#34;抽象(功能,特征等)。只有在筋疲力尽之后,我才开始引入宏。让我们先使用stringify
if let Some(v) = data.get(stringify!(x)) {
self.x = v.clone();
}
然后你可以提取一个宏:
macro_rules! thing {
($this: ident, $data: ident, $($name: ident),+) => {
$(
if let Some(v) = $data.get(stringify!($name)) {
$this.$name = v.clone();
}
)+
};
}
impl Container {
fn load_data(&mut self, data: &HashMap<String, String>) {
thing!(self, data, x, y, z);
}
}
fn main() {
let mut c = Container::default();
let d: HashMap<_, _> = vec![("x".into(), "alpha".into())].into_iter().collect();
c.load_data(&d);
println!("{:?}", c);
}
完全披露:我不认为这是个好主意。