Rust结构体更新语法不会获取所有权

5
#[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: 有更好的方法来解决这个问题吗?


我的问题是,如果结构体具有许多字段,克隆将创建一个结构体的实例car1的副本,仅使用其值分配给结构体的实例car2,而结构体的实例本身将存储这些值。假设x是存储struct Car的实例所需的内存,则:

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

需要3x内存,理论上只需要2x内存。

问题2:在实例化car2之后,car1.clone()会超出作用域,从而放弃内存吗?

如果是:这个克隆方法就可以使用,因为只需要临时多出一个x内存。

如果不是:那么是否有一种方法可以实现此目标,而无需额外的x内存或获取绑定本身的所有权。

1个回答

2
您的问题本质上是询问 ..car1.clone() 是否执行了部分克隆,仅克隆缺失的字段,例如对于 car2company 字段。

这是否可能进行优化?可能,但是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()会失去作用域,从而放弃内存吗?

是的。 car1.clone()中的model 在分配给car2后立即被删除。但是,company当然不会被删除,因为它被移动到了car2中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接