Rust如何移动不可复制的堆栈变量? [英] How does Rust move stack variables that are not Copyable?

查看:215
本文介绍了Rust如何移动不可复制的堆栈变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里记录了Rust的移动语义的一个很好的例子:Rust上的 Rust Move语义学通过示例网站.

There is a great example of Rust's move semantics documented here: Rust Move Semantics on the Rust By Example website.

我对所展示的两种情况都有基本的了解.第一个是原始元素如何具有新别名,而原始元素仍可以使用,因为最终结果是复制品,因为i32利用了Copy特性.这对我来说很有意义.

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. This makes good sense to me.

此外,出于许多充分的理由,第二个示例在具有多个引用堆上i32的别名方面也很有意义. Rust强制执行所有权规则,因此,既然已经创建了新的绑定,则无法使用原始别名.这有助于防止数据争用,双重释放等.

Additionally, for many good reasons the second example makes sense in terms of having multiple aliases that refer to an i32 on the heap. Rust enforces ownership rules and therefore the original alias cannot be used now that a new binding has been created. This helps prevent data-races, double frees, etc.

但是似乎没有讨论第三种情况. Rust如何实现未实现Copy特征的堆栈分配结构的移动?以下代码对此进行了说明:

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? 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);
}

我知道这一点:在上述情况下, Rust将在堆栈中分配Employee .上面的结构不实现Copy特征,因此在分配给新别名时不会被复制.这对我来说非常混乱,因为如果Employee结构分配在堆栈上并且还没有实现Copy特征,它将在哪里/如何移动?它会物理地移到do_something()的堆栈框架吗?

This I know: In the case above, Rust will allocate the Employee on the stack. The above struct does not implement the Copy trait and therefore will not be copied when assigned to a new alias. 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? Does it physically get moved to do_something()'s stack frame?

在解释这个难题时会提供帮助.

Any help is appreciated in explaining this conundrum.

推荐答案

它是否物理地移到了do_something()的堆栈框架上?

是的.非Copy类型的物理移动与Copy类型的完全相同:使用memcpy.您已经了解到,原始的Copy类型将逐字节复制到新位置(例如,新的堆栈帧)中.

Yes. Non-Copy types are physically moved exactly like Copy types are: with a memcpy. You already understood that primitive Copy-types are copied into the new location (new stack frame for example) byte-by-byte.

现在考虑使用Box的这种实现:

Now consider this implementation of Box:

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

有空的时候

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

然后在堆上分配了i32,并且Box将原始指针保存到该堆分配的内存中.请注意,直接Box(内部的原始指针)直接在堆栈上,而不在堆上!只是i32在堆上.

then an i32 is allocated on the heap and the Box saves the raw pointer to that heap allocated memory. Note that the Box directly (the raw pointer inside) is directly on the stack, not on the heap! Just the i32 is on the heap.

移动Box时,就像我刚才说的那样,它被memcpy修改.这意味着堆栈内容被复制(!!)...因此,仅指针被逐字节复制. i32没有第二个版本!

When the Box is moved, it is memcpyed, as I just said. 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!

Copy和非Copy类型在物理移动方面没有区别.唯一的区别是,编译器对这些类型执行不同的规则.

There is no difference between Copy and non-Copy types when it comes to moving physically. The only difference is that the compiler enforces different rules upon those types.

这篇关于Rust如何移动不可复制的堆栈变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆