Rust 在单个表达式中创建、初始化和运行的惯用方法

Rust 在单个表达式中创建、初始化和运行的惯用方法,rust,Rust,有时你会遇到这样的情况: let mut something = Something::new(); something.set_property_a("foo"); something.set_property_b("bar"); let result = something.result(); 您所需要的只是结果,但现在范围被某些东西污染了 在Kotlin中,您可以这样做(在其他版本中,但为了清晰起见,请使用详细版本): T.let(closure)只运行closure,将调用它的对象(S

有时你会遇到这样的情况:

let mut something = Something::new();
something.set_property_a("foo");
something.set_property_b("bar");
let result = something.result();
您所需要的只是结果,但现在范围被
某些东西污染了

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

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

在铁锈中可以做类似的事情吗?我想到的最接近的方法是:

let result = {
    let mut x = Something::new();
    x.set_property_a("foo");
    x.set_property_b("boo");
    x.result()
};
您可以使用。这是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);
}
#[派生(调试)]
构造某物{
属性a:字符串,
属性_b:String,
}
#[派生(调试,默认)]
结构构建器{
房地产:期权,
属性_b:String,
}
#[导出(调试)]
枚举生成错误{
阿诺塞特,
}
安装一些东西{
fn new()->Self{
Self::default()
}
fn带_a(mut self,a:String)->self{
self.property_a=Some(a);
自己
}
fn带_b(mut self,b:String)->self{
self.property_b=b;
自己
}
fn构建(自)->结果{
好的{
属性a:self.property\u a.ok\u或(BuildError::ANotSet)?,
property_b:self.property_b,
})
}
}
fn main(){
let thing=SomethingBuilder::new()
.with_a(“foo.into())
.with_b(“bar.into())
.build()//如果忽略了集合a,则返回BuildError
.unwrap();
println!(“{:?}”,东西);
}
例如,见


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

在这两种情况下,
x
不会泄漏到外部范围。你还想要什么?你的例子就是我认为的习惯用法。但是,我通常会继续将其提取到函数中。@JoshLee我不知道或不确认这是正确的方法,这似乎是,谢谢。旁注:为了完整性,我建议提供一个生成器作为API的一部分,但是如果在我的程序中我只“需要”一次或两次生成器,我只会使用块表达式。@MatthieuM。当然,对于一到两次的使用来说(大约30行,而不是4行),这是一种过度使用
#[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);
}