Rust 如何强制实现复制特征的类型移动?

Rust 如何强制实现复制特征的类型移动?,rust,Rust,默认情况下,自定义类型通过默认分配移动。通过实现Copytrait,我通过默认赋值获得了“浅拷贝语义”。我还可以通过实现Clonetrait来获得“深度复制语义” 是否有办法强制移动副本类型 我尝试使用move关键字和闭包(let new_id=move | | id;),但收到了一条错误消息。我还没有对闭包感兴趣,但是,从这里和那里看到它们,我认为这会起作用。新答案 有时我只是想让它对我尖叫“在这里输入一个新的值!” 那么答案是“不”。移动实现复制的类型时,源和目标将始终有效。移动未实现复制的

默认情况下,自定义类型通过默认分配移动。通过实现
Copy
trait,我通过默认赋值获得了“浅拷贝语义”。我还可以通过实现
Clone
trait来获得“深度复制语义”

是否有办法强制移动
副本
类型


我尝试使用
move
关键字和闭包(
let new_id=move | | id;
),但收到了一条错误消息。我还没有对闭包感兴趣,但是,从这里和那里看到它们,我认为这会起作用。

新答案

有时我只是想让它对我尖叫“在这里输入一个新的值!”

那么答案是“不”。移动实现
复制的类型时,源和目标将始终有效。移动未实现
复制的类型时,源将永远无效,目标将始终有效。没有语法或特征表示“让我选择实现
Copy
的类型此时是否充当
Copy

原始答案

有时我只是想说“是的,这个类型是Copy,但我真的不需要这个变量中的值了。这个函数接受一个arg by val,接受它。”


听起来您正试图手工完成优化器的工作。别担心,优化器会帮你做的。这样做的好处是不必担心它。

将可复制类型包装到另一个不实现
复制的类型中

struct不可复制(T);
fn main(){
设v0=不可复制(1);
设v1=v0;
println!(“{}”,v0.0);//错误:使用移动的值:`v0.0`
}

我不太明白你的问题,但你似乎很困惑。因此,我将解决这一困惑的根源:

<> P>拷贝/移动的C++概念我认为我得到的是正确的,但是“无论如何都是一个MimcPy”是,嗯,它在我读它的时候并不是非常直观的 在考虑Rust的移动语义时,忽略C++。C++故事比生锈的故事复杂得多,这非常简单。但是,用C++来解释RIST的语义是一团混乱。 TL;DR:拷贝是移动。移动就是复制。只有类型检查器知道差异。因此,当你想“强制移动”一个
复制
类型时,你是在要求你已经拥有的东西

我们有三种语义:

  • 设a=b
    其中
    b
    不是
    复制
  • 设a=b
    其中
    b
    复制
  • a=b.clone()
    其中
    b
    clone
注意:赋值和初始化之间没有什么有意义的区别(如在C++中)-赋值只需先
删除
s旧值即可

注意:函数调用参数的工作方式与赋值相同
f(b)
b
赋值给
f
的参数


第一件事优先。

a=b
始终执行
memcpy

这三种情况都是如此

  • 当您执行
    时,让a=b
    b
    memcpy
    'd进入
    a
  • 当您执行
    让a=b.clone()
    时,
    b.clone()
    的结果是
    memcpy
    'd进入
    a

移动

想象一下
b
是一个
Vec
Vec
如下所示:

{ &mut data, length, capacity }
{ is_valid, data }
当你写
时,让a=b
你就这样结束了:

b = { &mut data, length, capacity }
a = { &mut data, length, capacity }
b = { is_valid, data }
a = { is_valid, data }
这意味着
a
b
都引用
和mut数据
,这意味着我们有别名可变数据

类型系统不喜欢这样,因此表示我们不能再次使用
b
。任何对
b
的访问都将在编译时失败

注意:
a
b
不必为堆数据添加别名,这两种方法都不好用。例如,它们都可以是文件句柄-一个副本将导致文件关闭两次

注意:当涉及析构函数时,移动确实有额外的语义,但编译器无论如何都不允许您在具有析构函数的类型上编写
Copy


复制

想象一下
b
是一个
选项
选项
如下所示:

{ &mut data, length, capacity }
{ is_valid, data }
当你写
时,让a=b
你就这样结束了:

b = { &mut data, length, capacity }
a = { &mut data, length, capacity }
b = { is_valid, data }
a = { is_valid, data }
它们都可以同时使用。要告诉类型系统这种情况,可以将
选项
标记为
复制

注意:标记副本不会改变代码的功能。它只允许更多的代码。如果删除
副本
实现,代码将出错或执行完全相同的操作。同样,将非
复制
类型标记为
复制
不会更改任何已编译代码


克隆

假设您要复制一个
Vec
,然后。您实现了
克隆
,它将生成一个新的
向量
,并且

let a = b.clone()
这将执行两个步骤。我们从以下几点开始:

b = { &mut data, length, capacity }
运行
b.clone()
会为我们提供一个额外的临时右值

b = { &mut data, length, capacity }
    { &mut copy, length, capacity } // temporary
运行
让a=b.clone()
memcpy
将其放入
a

b = { &mut data, length, capacity }
    { &mut copy, length, capacity } // temporary
a = { &mut copy, length, capacity }
由于
Vec
不是
Copy
,因此类型系统阻止了对临时文件的进一步访问


但是效率呢?

到目前为止,我忽略了一件事,那就是移动和复制可以省略。生锈保证了某些琐碎的动作和复制品将被省略

因为编译器(在生命周期检查之后)在b中看到相同的结果