用于创建,初始化和运行单个表达式的惯用方法

时间:2017-12-14 21:04:32

标签: rust

有时你会有这样的事情:

let mut something = Something::new();
something.set_property_a("foo");
something.set_property_b("bar");
let result = something.result();

你所需要的只是结果,但现在范围被something污染了。

在Kotlin中,您可以这样做(在其他版本中,但为了清晰起见使用详细的):

val result = Something().let { x ->
    x.propertyA = "foo"
    x.propertyB = "bar"
    x.result()
}

T.let(closure)只运行闭包,将调用它的对象(Something的实例)作为参数,并返回闭包返回的内容。非常轻巧,简单的概念,但非常有帮助。

在Rust中可以做类似的事吗?我最接近的是:

let result = {
    let mut x = Something::new();
    x.set_property_a("foo");
    x.set_property_b("boo");
    x.result()
};

1 个答案:

答案 0 :(得分:2)

您可以使用builder pattern。这是Rust中用来实现你想要的东西的惯用方法:

#[derive(Debug)]
struct Something {
    property_a: String,
    property_b: String,
}

#[derive(Debug, Default)]
struct SomethingBuilder {
    property_a: Option<String>,
    property_b: String,
}

#[derive(Debug)]
enum BuildError {
    ANotSet,
}

impl SomethingBuilder {
    fn new() -> Self {
        Self::default()
    }

    fn with_a(mut self, a: String) -> Self {
        self.property_a = Some(a);
        self
    }

    fn with_b(mut self, b: String) -> Self {
        self.property_b = b;
        self
    }

    fn build(self) -> Result<Something, BuildError> {
        Ok(Something {
            property_a: self.property_a.ok_or(BuildError::ANotSet)?,
            property_b: self.property_b,
        })
    }
}

fn main() {
    let thing = SomethingBuilder::new()
        .with_a("foo".into())
        .with_b("bar".into())
        .build() // returns BuildError if set_a is left out
        .unwrap();

    println!("{:?}", thing);
}

例如,请参阅this real world usage

在构建器结构中,您可以在调用build方法时执行所需的所有验证。如果一切正常,您可以返回新构建的struct。此模式的优点是代码的可读性(无“污染”)保证构建的struct完全有效的用户。