2017-06-27 52 views
2

出于解释性编程语言的习惯,我想根据它们的关键字重写许多值。我认为我会将所有信息存储在为此项目准备的结构中。于是我开始迭代:如何通过字符串名称设置结构体字段值?

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

我很困惑,如果它们不是您要使用的键,那么'x','y'和'z'是什么?你是否试图根据地图内容向结构添加额外的字段? – loganfsmyth

+0

@loganfsmyth对不起,我忘了更换矢量内的名字。现在看起来应该如此。 – Maxie

回答

2

对于宏,我总是主张从直接代码开始,然后看看有什么重复。在这种情况下,我们会与

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

注启动差数:

  1. 的结构必须采取&mut self
  2. 检查一个值是否存在然后单独获取它是低效的。
  3. 我们需要克隆这个值,因为我们只有一个参考。
  4. 我们不能在String中存储Option

一旦你有你的代码工作,你可以看到如何抽象的东西。 总是首先尝试使用“更轻”的抽象(函数,特征等)。只有在耗尽之后,我才会开始引入宏。让我们通过使用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); 
} 

全面披露:我不认为这是一个好主意。

相关问题