Rust如何知道哪些类型拥有资源?

cor*_*zza 4 heap pointers ownership rust

如果有一个指向某个堆分配内存的框指针,我认为Rust具有"硬编码"的所有权知识,因此当通过调用某个函数传输所有权时,资源会被移动,并且函数中的参数是新的所有者.

但是,例如,对于矢量,这是怎么发生的?他们也"拥有"他们的资源,所有权机制适用于盒子指针 - 但它们是存储在变量本身的常规值,而不是指针.在这种情况下,Rust(知道)如何应用所有权机制?

我可以创建自己拥有资源的类型吗?

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)

请注意,这里绝对没有魔法 - 默认情况下,默认情况下,每种类型的每个值的行为与上面的示例相同.默认情况下,您或其他人创建的每个结构或枚举的值都将被移动.

另一个重要的事情是你可以给每个类型一个析构函数,也就是说,当这个类型的值超出范围并被销毁时调用的一段代码.例如,与相关的存储器相关联VecBox将释放相应存储器的析构函数.可以通过实现Droptrait 来声明析构函数:

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.另一方面,结构类似VecBox不是Copy- 它们故意不实现它,因为它们的字节副本将导致双重释放,因为它们的析构函数可以在同一指针上运行两次.

Copy上面的一点是我身边的一个小小的题外话,只是为了给出更清晰的画面.Rust中的所有权基于移动语义.当我们说某些价值拥有某些东西时,比如" Box<T>拥有给定的东西T",我们指的是它们之间的语义联系,而不是神奇的东西或内置于语言中的东西.它只是大多数这样的值,如VecBox不实现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.

  • 请注意,基本类型集还包括原始指针`*mut T`和`*const T`,它们用于执行`Box`和`Vec`以及其他容器类型.如果不是'Drop` impl,`Box`和`Vec`可能完全是`Copy` - 它只是'不安全'而且在语义错误. (4认同)
  • 由于它经常让人绊倒,请注意移动和副本在运行时是相同的 - 只有类型检查器知道差异.两者最终都是一个浅薄的"memcpy". (3认同)