【问题标题】:Is using to_owned() the idiomatic way to update a struct in place?使用 to_owned() 是更新结构的惯用方式吗?
【发布时间】:2017-05-16 03:10:08
【问题描述】:

我正在使用链式方法更新 Rust 结构。我找到了一种方法来做到这一点,但我不确定我下面的代码是否是惯用的 Rust 而不是一种解决方法。

特别是,我在链式方法的末尾使用了.to_owned() 来返回借用的结构。代码编译并且工作得很好。这是最小的例子。

//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
    run: i32,
    year: i32,
}
impl ModelDataCapture {
    pub fn new() -> Self {
        ModelDataCapture::default()
    }
    pub fn set_run(&mut self, run: i32) -> &mut ModelDataCapture {
        self.run = run;
        self
    }
    pub fn set_year(&mut self, year: i32) -> &mut ModelDataCapture {
        self.year = year;
        self
    }
}

//main.rs
let data_capture = ModelDataCapture::new()
    .set_run(0)
    .set_year(1)
    .to_owned(); // <<< QUESTION

println!("here is the data capture {:?}", data_capture);

这是对结构进行就地修改的正确方法吗?如果我没有在链的末尾包含 .to_owned() 方法,编译将失败并显示临时变量的寿命不够长的消息。

【问题讨论】:

  • 你可能对这个箱子感兴趣 github.com/colin-kiegel/rust-derive-builder#how-it-works :)
  • @kennytm 感谢您的提示。是的,在我开始使用快捷方式之前,我看到了那个板条箱并且只是想练习编写自己的构建器:)。但我会更多地研究一下派生构建器箱。我只是想确保我可以包含我想要包含的输入验证逻辑。

标签: struct rust method-chaining borrow-checker


【解决方案1】:

您的代码“有效”,但对我来说没有意义。它:

  • 创造价值
  • 改变值
  • 克隆值
  • 丢弃原始值

看到效率低下了吗?此外,所有“就地突变”都被完全丢弃,因此没有任何好处。

我通常会引入一个绑定来改变:

let mut data_capture = ModelDataCapture::new();
data_capture.set_run(0).set_year(1);

或者一路创建一个具有 finishbuild 等价物的构建器

#[derive(Debug)]
struct ModelDataCapture {
    run: i32,
    year: i32,
}

#[derive(Debug, Default)]
struct ModelDataCaptureBuilder {
    run: i32,
    year: i32,
}

impl ModelDataCaptureBuilder {
    fn set_run(self, run: i32) -> Self {
        ModelDataCaptureBuilder { run, ..self }
    }

    fn set_year(self, year: i32) -> Self {
        ModelDataCaptureBuilder { year, ..self }
    }

    fn build(self) -> ModelDataCapture {
        let ModelDataCaptureBuilder { run, year } = self;
        ModelDataCapture { run, year }
    }
}

fn main() {
    let data_capture = ModelDataCaptureBuilder::default().set_run(0).set_year(1).build();

    println!("here is the data capture {:?}", data_capture);
}

请参阅Do Rust builder patterns have to use redundant struct code?,了解更多镜像构建项目的构建器示例。

您可以在第一个示例中按值使用self,但在大多数情况下这很烦人,因为您始终必须记住绑定结果。

【讨论】:

  • 好的,很好。是的,当我在绑定之前链接方法时,我明白你所说的创建、变异、克隆想法的意思。这就是为什么我想知道奇怪的.to_owned() 方法。谢谢你的提示。我开始比以前更好地掌握这个窍门了。
  • 在使用对象的设置器中直接使用移动​​语义不是更好吗? IE。将set_run 定义为fn set_run(mut self, run: i32) -&gt; Self { self.run = run; self },以此类推。尽管编译器可能足够聪明,可以将两者优化到完全相同的输出,但明确更新单个字段会感觉更高效且更清晰。
【解决方案2】:

您可以更改函数以获取对 self 的所有权并返回 self。 因为每个“setter”方法都返回 self 的所有权,所以这段代码应该可以很好地运行。 欲了解更多信息,请查看rust book

//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
    run: i32,
    year: i32,
}
impl ModelDataCapture {
    pub fn new() -> Self {
        ModelDataCapture::default()
    }
    pub fn set_run(mut self, run: i32) -> ModelDataCapture {
        self.run = run;
        self
    }
    pub fn set_year(mut self, year: i32) -> ModelDataCapture {
        self.year = year;
        self
    }
}

fn main() {
    //main.rs
    let data_capture = ModelDataCapture::new().set_run(0).set_year(1);

    println!("here is the data capture {:?}", data_capture);
}

【讨论】:

    猜你喜欢
    • 2023-03-09
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多