Использует ли to_owned () идиоматический способ обновления структуры на месте?

Я играл с обновлением структуры 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() в конец цепочки, компиляция завершится ошибкой с сообщением о том, что временная переменная не живет достаточно долго.


person krishnab    schedule 16.05.2017    source источник
comment
Возможно, вас заинтересует этот ящик github.com/colin-kiegel / rust-derive-builder # как это работает :)   -  person kennytm    schedule 16.05.2017
comment
@kennytm спасибо за подсказку. Да, я видел этот ящик и просто пытался попрактиковаться в написании собственных конструкторов, прежде чем начал использовать ярлыки :). Но я еще немного разберусь с этим ящиком производного конструктора. Я просто хочу убедиться, что могу включить логику проверки ввода, которую хочу включить.   -  person krishnab    schedule 16.05.2017


Ответы (1)


Ваш код «работает», но для меня не имеет смысла. Это:

  • Создает значение
  • Изменяет значение
  • Клонирует значение
  • Выбрасывает исходное значение

Видите неэффективность? Кроме того, полностью отбрасываются все «мутации на месте», так что от этого нет никакой пользы.

Я бы обычно ввел привязку для изменения:

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

Или пройдите весь путь и создайте конструктор с эквивалентом finish или build

#[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);
}

См. Должны ли шаблоны построителя Rust использовать избыточный структурный код? для получения дополнительных примеров построителей, которые отражают построенные элементы.

В первом примере вы можете взять self по значению, но в большинстве случаев это раздражает, так как вы всегда должны помнить о привязке результата.

person Shepmaster    schedule 16.05.2017
comment
Хорошо, отлично. Да, я понимаю, что вы имеете в виду под идеей создания, изменения, клонирования, когда я связываю методы перед связыванием. Вот почему я задумался о странном .to_owned() методе. Спасибо за совет. Я начинаю понимать это лучше, чем раньше. - person krishnab; 16.05.2017
comment
Не лучше ли было бы напрямую использовать семантику перемещения в установщиках, которые все равно потребляют объект? Т.е. определите set_run как fn set_run(mut self, run: i32) -> Self { self.run = run; self } и так далее. Хотя компилятор может быть достаточно умен, чтобы оптимизировать и то, и другое для получения одного и того же вывода, явное указание на обновление одного поля кажется более эффективным и несколько более ясным. - person user4815162342; 16.05.2017