Синтаксис обновления структуры Rust без принятия права собственности

#rust

#Ржавчина

Вопрос:

 #[derive(Debug)]
struct Car {
    company: String,
    model: String,
    cost: i32
}

fn main() {
    let car1 = Car {
        company: String::from("Ford"),
        model: String::from("123xyz"),
        cost: 50000
    };
    let car2 = Car {
        model: String::from("987pqr"),
        cost: 47000,
        ..car1
    };
    println!("{:#?}", car2);
    println!("{:#?}", car1.company);
}
 

Здесь компилятор правильно сообщает мне:

 println!("{:#?}", car1.company);
                  ^^^^^^^^^^^^ value borrowed here after move
move occurs because `car1.company` has type `String`, which does not implement the `Copy` trait
 

Я понимаю, что экземпляр String находится в куче, и именно поэтому его нельзя скопировать, право собственности было перемещено в car2.company . Я могу решить этот вариант использования примерно так:

 #[derive(Debug, Clone)]
struct Car {
    company: String,
    model: String,
    cost: i32
}

fn main() {
    let car1 = Car {
        company: String::from("Ford"),
        model: String::from("123xyz"),
        cost: 50000
    };
    let car2 = Car {
        model: String::from("987pqr"),
        cost: 47000,
        ..car1.clone()
    };
    println!("{:#?}", car2);
    println!("{:#?}", car1.company);
}
 

Вопрос 1: Есть ли лучший способ сделать это?


Теперь моя проблема заключается в том, что если в структуре было много полей, clone создал бы копию экземпляра car1 структуры только для того, чтобы использовать ее значения для присвоения экземпляру car2 структуры, который сам будет хранить значения. Если x — это память, необходимая для хранения экземпляра struct Car ,

  • car1: x
  • car1.clone: x
  • car2: x

требуется 3x памяти, где технически должно было потребоваться только 2x памяти.

Вопрос 2: После car2 создания экземпляра car1.clone() выйдет из области видимости и, следовательно, откажется от памяти?

Если да: этот метод клонирования подойдет, поскольку требуется только временная дополнительная память x.

Если нет: тогда есть ли способ достичь этой цели без необходимости использования дополнительной памяти x или получения права собственности на саму привязку.

Ответ №1:

По сути, вы спрашиваете, ..car1.clone() выполняет ли частичное клонирование и только клонирует недостающие поля, т. Е. company for car2 .

Будет ли это возможной оптимизацией? Возможно, но clone() может сделать что угодно, поэтому может быть не так просто выполнить «частичное clone() «. Итак, ответ отрицательный, car1.clone() полностью клонирован.

Вопрос 1: Есть ли лучший способ сделать это?

Я предполагаю, что вы используете синтаксис обновления ( .. ), потому что у вас значительно больше полей. Однако, если нет, то, чтобы избежать ненужного клонирования model . Затем вы можете явно клонировать и назначать car1.company .

Однако, я думаю, вы это уже знаете. Но если вы хотите избежать ненужного клонирования model . Тогда это альтернативное решение.

 let car2 = Car {
    company: car1.company.clone(),
    model: String::from("987pqr"),
    cost: 47000,
};
 

Вопрос 2: После car2 создания экземпляра car1.clone() выйдет из области видимости и, следовательно, откажется от памяти?

Да. model from car1.clone() удаляется сразу после назначения to car2 . Однако, company конечно, не отбрасывается, поскольку он перемещается car2 .