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中看到相同的结果