Vla*_*eev 12
tl; dr:Rust中的"拥有"类型并不是一些神奇的东西,它们肯定不会硬编码到编译器或语言中.它们只是以某种方式编写的类型(不实现Copy
并且可能具有析构函数)并且具有通过不可复制性和析构函数强制执行的某些语义.
在其核心中,Rust的所有权机制非常简单,并且具有非常简单的规则.
首先,让我们来定义什么举动是.这很简单 - 当一个值以新名称变为可用并且停止以旧名称提供时,该名称将被移动:
struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is no longer accessible here, trying to use it will cause a compiler error
Run Code Online (Sandbox Code Playgroud)
将值传递给函数时会发生同样的事情:
fn do_something(x: X) {}
let x1 = X(12);
do_something(x1);
// x1 is no longer accessible here
Run Code Online (Sandbox Code Playgroud)
请注意,这里绝对没有魔法 - 默认情况下,默认情况下,每种类型的每个值的行为与上面的示例相同.默认情况下,您或其他人创建的每个结构或枚举的值都将被移动.
另一个重要的事情是你可以给每个类型一个析构函数,也就是说,当这个类型的值超出范围并被销毁时调用的一段代码.例如,与相关的存储器相关联Vec
或Box
将释放相应存储器的析构函数.可以通过实现Drop
trait 来声明析构函数:
struct X(u32);
impl Drop for X {
fn drop(&mut self) {
println!("Dropping {}", x.0);
}
}
{
let x1 = X(12);
} // x1 is dropped here, and "Dropping 12" will be printed
Run Code Online (Sandbox Code Playgroud)
有一种方法可以通过实现Copy
将类型标记为可自动复制的特征来选择退出不可复制性 - 它的值将不再被移动而是被复制:
#[derive(Copy, Clone)] struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is still available here
Run Code Online (Sandbox Code Playgroud)
副本按字节顺序完成 - x2
将包含与字节相同的副本x1
.
不是每种类型都可以制造Copy
- 只有那些有Copy
内部而且没有实现的类型 Drop
.所有原始类型(&mut
引用除了包括*const
和*mut
原始指针)都Copy
在Rust中,因此可以创建仅包含基元的每个结构Copy
.另一方面,结构类似Vec
或Box
不是Copy
- 它们故意不实现它,因为它们的字节副本将导致双重释放,因为它们的析构函数可以在同一指针上运行两次.
Copy
上面的一点是我身边的一个小小的题外话,只是为了给出更清晰的画面.Rust中的所有权基于移动语义.当我们说某些价值拥有某些东西时,比如" Box<T>
拥有给定的东西T
",我们指的是它们之间的语义联系,而不是神奇的东西或内置于语言中的东西.它只是大多数这样的值,如Vec
或Box
不实现Copy
,因此移动而不是复制,它们(也可选)有一个析构函数,清除这些类型可能为它们分配的任何内容(内存,套接字,文件等).
鉴于上述情况,您当然可以编写自己的"拥有"类型.这是惯用Rust的基石之一,标准库和外部库中的许多代码都是以这种方式编写的.例如,某些C API提供了创建和销毁对象的功能.在Rust中编写一个"拥有"包装器非常容易,它可能非常接近你所要求的:
extern {
fn create_widget() -> *mut WidgetStruct;
fn destroy_widget(w: *mut WidgetStruct);
fn use_widget(w: *mut WidgetStruct) -> u32;
}
struct Widget(*mut WidgetStruct);
impl Drop for Widget {
fn drop(&mut self) {
unsafe { destroy_widget(self.0); }
}
}
impl Widget {
fn new() -> Widget { Widget(unsafe { create_widget() }) }
fn use_it(&mut self) -> u32 {
unsafe { use_widget(self.0) }
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以说Widget
拥有一些外国资源*mut WidgetStruct
.