简体   繁体   English

Rust如何移动不可复制的堆栈变量?

[英]How does Rust move stack variables that are not Copyable?

There is a great example of Rust's move semantics documented here: Rust Move Semantics on the Rust By Example website. 这里记录了Rust的移动语义的一个很好的例子:在Rust By Example网站上的Rust Move Semantics

I have a basic understanding of both cases demonstrated. 我对两个案例都有基本的了解。 The first being how a primitive can have a new alias and the original can still be used because the end result is a copy seeing as i32 utilizes the Copy trait. 第一个是原语如何拥有一个新的别名,原始的仍然可以使用,因为最终结果是一个副本,因为i32使用了Copy特征。 This makes good sense to me. 这对我来说很有意义。

Additionally, for many good reasons the second example makes sense in terms of having multiple aliases that refer to an i32 on the heap. 此外,由于许多充分的理由,第二个示例在具有多个引用堆上的i32别名方面是i32的。 Rust enforces ownership rules and therefore the original alias cannot be used now that a new binding has been created. Rust强制执行所有权规则,因此现在无法使用原始别名创建新绑定。 This helps prevent data-races, double frees, etc. 这有助于防止数据争用,双重释放等。

But it would seem there is a third case which is not talked about. 但似乎还有第三个案例没有被谈到。 How does Rust implement moves of stack allocated structs that do not implement the Copy trait? Rust如何实现堆栈分配结构的移动,这些结构没有实现Copy特征? This is illustrated with the following code: 使用以下代码对此进行说明:

#[derive(Debug)]
struct Employee{
    age: i32,
}

fn do_something(m: Employee){
    println!("{:?}", m);
}

fn main() {
    let x = Employee {
        age: 25,
    };

    do_something(x);

    //compiler error below because x has moved
    do_something(x);
}

This I know: In the case above, Rust will allocate the Employee on the stack . 我知道:在上面的例子中, Rust将在堆栈上分配Employee The above struct does not implement the Copy trait and therefore will not be copied when assigned to a new alias. 上述结构不实现Copy特征 ,因此在分配给新别名时不会被复制。 This is very confusing to me because if the Employee struct is allocated on the stack and also does not implement the Copy trait where/how does it move? 这对我来说非常困惑,因为如果在堆栈上分配Employee结构并且还没有实现Copy trait where / how如何移动? Does it physically get moved to do_something() 's stack frame? 它是否实际上被移动到do_something()的堆栈帧?

Any help is appreciated in explaining this conundrum. 在解释这个难题时,任何帮助都会受到赞赏。

Does it physically get moved to do_something() 's stack frame? 它是否实际上被移动到do_something()的堆栈帧?

Yes. 是。 Non- Copy types are physically moved exactly like Copy types are: with a memcpy . Copy类型的物理移动方式与Copy类型完全相同:使用memcpy You already understood that primitive Copy -types are copied into the new location (new stack frame for example) byte-by-byte. 您已经了解原始Copy -types Copy逐字节地复制到新位置(例如,新的堆栈帧)。

Now consider this implementation of Box : 现在考虑Box这个实现:

struct Box<T> {
    ptr: *const T,
}

When you have 当你有

let b = Box::new(27i32);
do_something(b);    // `b` is moved into `do_something`

then an i32 is allocated on the heap and the Box saves the raw pointer to that heap allocated memory. 然后在i32分配i32Box将原始指针保存到堆分配的内存中。 Note that the Box directly (the raw pointer inside) is directly on the stack, not on the heap! 请注意, Box直接(内部的原始指针)直接在堆栈上,而不是在堆上! Just the i32 is on the heap. 只是i32在堆上。

When the Box is moved, it is memcpy ed, as I just said. Box被移动时,就像我刚刚说的那样,它被memcpy This means that the stack contents are copied (!!)... thus just the pointer is copied byte-by-byte. 这意味着堆栈内容被复制(!!)...因此只需逐个字节地复制指针。 There isn't a second version of the i32 ! 没有i32的第二个版本!

There is no difference between Copy and non- Copy types when it comes to moving physically. 在物理移动方面, Copy和非Copy类型之间没有区别。 The only difference is that the compiler enforces different rules upon those types. 唯一的区别是编译器对这些类型强制执行不同的规则。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM