Rust 铁锈中的移动语义是什么?
在Rust中,有两种可能引用Rust 铁锈中的移动语义是什么?,rust,move-semantics,ownership,Rust,Move Semantics,Ownership,在Rust中,有两种可能引用 借用,即获取引用,但不允许对引用目的地进行变异。&运算符从值借用所有权 可变借用,即引用以改变目的地。&mut运算符可变地从值借用所有权 报告说: 首先,任何借贷的持续时间不得超过 主人。第二,你可能有这两种类型中的一种或另一种 借款,但不能同时借款: 对资源的一个或多个引用(&T) 只有一个可变引用(&mut T) 我相信引用就是创建一个指向该值的指针,并通过指针访问该值。如果有更简单的等效实现,编译器可以对此进行优化 但是,我不理解移动的含义以及它是如何实现
&
运算符从值借用所有权&mut
运算符可变地从值借用所有权- 对资源的一个或多个引用(
)&T
- 只有一个可变引用(
)&mut T
Copy
特征的类型,它意味着复制,例如通过从源中按顺序分配结构成员,或通过memcpy()
。对于小型结构或基本体,此副本是有效的
对于移动
这个问题并不是复制的,因为Rub和C++是不同的语言,移动语义在两者之间是不同的。 < P>当你移动一个项目时,你正在转移该项目的所有权。这是生锈的关键成分
假设我有一个结构,然后我将结构从一个变量分配到另一个变量。默认情况下,这将是一个移动,我已经转移了所有权。编译器将跟踪此所有权更改,并阻止我再使用旧变量:
pub struct Foo {
value: u8,
}
fn main() {
let foo = Foo { value: 42 };
let bar = foo;
println!("{}", foo.value); // error: use of moved value: `foo.value`
println!("{}", bar.value);
}
它是如何实施的
从概念上讲,移动某物不需要做任何事情。在上面的例子中,当我分配给不同的变量时,没有理由在某个地方实际分配空间,然后移动分配的数据。我实际上不知道编译器是做什么的,它可能会根据优化的级别而改变
但出于实际目的,您可以认为,当您移动某个对象时,表示该对象的位会被复制,就像通过memcpy
一样。这有助于解释当您将变量传递给使用它的函数时,或者当您从函数返回值时会发生什么(同样,优化器可以做其他事情来提高效率,这只是概念上的):
“但是等等!”,你说,“memcpy
只在实现Copy
!”的类型中起作用。这在很大程度上是正确的,但最大的区别在于,当一个类型实现Copy
时,源和目标都可以在复制后使用
移动语义的一种思考方式与复制语义相同,但增加了一个限制,即被移动的对象不再是可使用的有效项
然而,从另一个角度考虑它通常更容易:你能做的最基本的事情是转移/放弃所有权,而复制东西的能力是一种额外的特权。这就是锈菌塑造它的方式
这对我来说是个棘手的问题!使用Rust一段时间后,移动语义是自然的。让我知道我遗漏了哪些部分或解释得不好。请让我回答我自己的问题。我遇到了麻烦,但在这里我问了一个问题。现在我明白了: 移动是价值的所有权转移 例如,赋值
设x=a代码>转移所有权:首先a
拥有该值。在之后,让x
拥有该值。锈蚀后禁止使用a
事实上,如果你做了println!(“a:{:?}”,a)代码>在之后让
Rust编译器说:
error: use of moved value: `a`
println!("a: {:?}", a);
^
完整示例:
#[derive(Debug)]
struct Example { member: i32 }
fn main() {
let a = Example { member: 42 }; // A struct is moved
let x = a;
println!("a: {:?}", a);
println!("x: {:?}", x);
}
这个移动意味着什么
这个概念似乎来自C++11。A说:
从客户机代码的角度来看,选择“移动”而不是“复制”意味着您不关心源代码的状态会发生什么变化
啊哈。C++11不关心源代码会发生什么。因此,在这种情况下,Rust可以在移动后自由决定禁止使用源
它是如何实施的
我不知道。但我可以想象锈实际上什么都没有x
只是相同值的不同名称。名称通常被编译掉(当然调试符号除外)。因此,无论绑定的名称是a
还是x
,机器代码都是相同的
<>看起来C++在复制构造函数删除中也一样。
什么都不做是最有效率的。将值传递给函数,也会导致所有权的转移;这与其他示例非常相似:
struct Example { member: i32 }
fn take(ex: Example) {
// 2) Now ex is pointing to the data a was pointing to in main
println!("a.member: {}", ex.member)
// 3) When ex goes of of scope so as the access to the data it
// was pointing to. So Rust frees that memory.
}
fn main() {
let a = Example { member: 42 };
take(a); // 1) The ownership is transfered to the function take
// 4) We can no longer use a to access the data it pointed to
println!("a.member: {}", a.member);
}
因此,预期误差为:
post_test_7.rs:12:30: 12:38 error: use of moved value: `a.member`
语义
锈迹是一种被称为:
仿射类型是施加较弱约束的线性类型的一个版本,对应于仿射逻辑仿射资源只能使用一次,而线性资源必须使用一次
不是Copy
,因此被移动的类型是仿射类型:您可以使用它们一次,也可以不使用它们,而不使用其他类型
Rust在其以所有权为中心的世界观(*)中将此定义为所有权转让
(*)一些研究锈病的人比我在CS中的资历要高得多,他们故意实施了仿射型系统;然而,与Haskell公开math-y/cs-y概念相反,Rust倾向于公开更多的实用概念
注意:有人可能会认为,从标记为#[必须使用]
的函数返回的仿射类型实际上是我阅读的线性类型
实施
post_test_7.rs:12:30: 12:38 error: use of moved value: `a.member`
fn main() {
let s = "Hello, World!".to_string();
let t = s;
println!("{}", t);
}
%_5 = alloca %"alloc::string::String", align 8
%t = alloca %"alloc::string::String", align 8
%s = alloca %"alloc::string::String", align 8
%0 = bitcast %"alloc::string::String"* %s to i8*
%1 = bitcast %"alloc::string::String"* %_5 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* %0, i64 24, i32 8, i1 false)
%2 = bitcast %"alloc::string::String"* %_5 to i8*
%3 = bitcast %"alloc::string::String"* %t to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %2, i64 24, i32 8, i1 false)