如果尚未设置多个选项,如何设置嵌套在多个选项中的值?

时间:2018-03-21 21:06:47

标签: rust config mutability

我有一个配置设置,例如:

#[derive(Debug, Deserialize, Serialize)]
struct Config {
    defaults: Option<Default>,
}

#[derive(Debug, Deserialize, Serialize)]
struct Default {
    duration: Option<Millis>,
}

#[derive(Serialize, Deserialize, Debug)]
struct Millis(u64);

值为let cfg: &mut Config,我怎样才能轻松设置此值的持续时间?

我尝试了这个,如果值不是从那里开始就会发生恐慌:

*cfg.default.as_mut().unwrap().duration.as_mut().unwrap() = Millis(1234)

我没有找到绕过unwrap的方法来创建除此之外的按需值,这更加冗长......

if cfg.defaults.is_none() {
    cfg.defaults = Some(Default { duration: None });
}

if cfg.defaults.as_mut().unwrap().duration.is_none() {
    cfg.defaults.as_mut().unwrap().duration = Some(Millis(1234));
}

什么&#34; The Way&#34;这样做?

2 个答案:

答案 0 :(得分:4)

这是get_or_insert方法的用途:

#[derive(Debug)]
struct Config {
    defaults: Option<Default>,
}

#[derive(Debug)]
struct Default {
    duration: Option<Millis>,
}

#[derive(Debug)]
struct Millis(u64);

fn main() {
    let mut config = Config { defaults: None };

    config
        .defaults
        .get_or_insert(Default { duration: None })
        .duration
        .get_or_insert(Millis(0))
        .0 = 42;

    // Config { defaults: Some(Default { duration: Some(Millis(42)) }) }
    println!("{:?}", config);
}

(link to playground)

答案 1 :(得分:0)

我认为最好的方法是使用模式匹配:

if let Some(Config { defaults: Some(Default { duration: Some(ref mut millis) }) }) = cfg {
    *millis = 1234;
}

或者,使用嵌套的if let s:

if let Some(Config { ref mut defaults }) = cfg {
    if let Some(Default { ref mut duration }) = *defaults {
        *duration = Some(Millis(1234))
    }
}

但是,这不会按需创建值。据我所知,没有简单的无样板的方法。其中一种方法是定义自己的访问器方法,这些方法将在访问时处理默认实例化:

impl Config {
    fn defaults(&mut self) -> &mut Default {
        if let Some(ref mut defaults) = *self.defaults {
            defaults
        } else {
            self.defaults = Some(Defaults::new());  // assuming that Defaults::new() exists
            self.defaults.as_mut().unwrap()
        }
    }
}

如果您对每个结构的每个字段都有这样的方法,那么您将能够这样做:

*cfg.defaults().duration() = 1234;