tl;dr:Rust 中的“拥有”类型并不是什么魔法,而且它们肯定不会硬编码到编译器或语言中。它们只是以某种方式编写的类型(不实现 Copy 并且可能具有析构函数)并且具有通过不可复制性和析构函数强制执行的某些语义。
在其核心,Rust 的所有权机制非常简单,规则也非常简单。
首先,让我们定义move是什么。这很简单——当一个值以新名称可用并且不再以旧名称可用时,就称它为 moved:
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
将值传递给函数时也会发生同样的情况:
fn do_something(x: X) {}
let x1 = X(12);
do_something(x1);
// x1 is no longer accessible here
请注意,这里 绝对没有魔法 - 只是默认情况下 every 类型的 every 值的行为与上述示例中的行为类似.您或其他人默认创建的每个结构或枚举的值将被移动。
另一个重要的事情是你可以给每个类型一个析构函数,也就是说,当这个类型的值超出范围并被销毁时调用的一段代码。例如,与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
有一种方法可以通过实现 Copy 特征来选择退出不可复制性,该特征将类型标记为自动可复制 - 它的值将不再被移动而是被复制:
#[derive(Copy, Clone)] struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is still available here
复制按字节完成 - x2 将包含 x1 的字节相同副本。
并非所有类型都可以制作Copy - 只有那些具有Copy 内部并且不实现 Drop 的类型。所有原始类型(&mut 引用除外,但包括 *const 和 *mut 原始指针)在 Rust 中都是 Copy,因此每个仅包含原始类型的结构都可以制作为 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) }
}
}
现在你可以说Widget拥有一些由*mut WidgetStruct代表的外国资源。