简体   繁体   English

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

[英]How does Rust know which types own resources?

When one has a box pointer to some heap-allocated memory, I assume that Rust has 'hardcoded' knowledge of ownership, so that when ownership is transferred by calling some function, the resources are moved and the argument in the function is the new owner. 如果有一个指向某个堆分配内存的框指针,我认为Rust具有“硬编码”的所有权知识,因此当通过调用某个函数传输所有权时,资源会被移动 ,并且函数中的参数是新的所有者。

However, how does this happen for vectors for example? 但是,例如,对于矢量,这是怎么发生的? They too 'own' their resources, and ownership mechanics apply like for box pointers -- yet they are regular values stored in variables themselves , and not pointers. 他们也“拥有”他们的资源,所有权机制适用于盒子指针 - 但它们是存储在变量本身的常规值,而不是指针。 How does Rust (know to) apply ownership mechanics in this situation? 在这种情况下,Rust(知道)如何应用所有权机制?

Can I make my own type which owns resources? 我可以创建自己拥有资源的类型吗?

tl;dr: "owning" types in Rust are not some magic and they are most certainly not hardcoded into the compiler or language. tl; dr:Rust中的“拥有”类型并不是一些神奇的东西,它们肯定不会硬编码到编译器或语言中。 They are just types which written in a certain way (do not implement Copy and likely have a destructor) and have certain semantics which is enforced through non-copyability and the destructor. 它们只是以某种方式编写的类型(不实现Copy并且可能具有析构函数)并且具有通过不可复制性和析构函数强制执行的某些语义。

In its core Rust's ownership mechanism is very simple and has very simple rules. 在其核心中,Rust的所有权机制非常简单,并且具有非常简单的规则。

First of all, let's define what move is. 首先,让我们定义是什么 It is simple - a value is said to be moved when it becomes available under a new name and stops being available under the old name: 这很简单 - 当一个值以新名称变为可用并且在旧名称下停止可用时,该名称将被移动

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

Same thing happens when you pass a value into a function: 将值传递给函数时会发生同样的事情:

fn do_something(x: X) {}

let x1 = X(12);
do_something(x1);
// x1 is no longer accessible here

Note that there is absolutely no magic here - it is just that by default every value of every type behaves like in the above examples. 请注意,这里绝对没有魔法 - 默认情况下,默认情况下, 每种类型的每个值的行为与上面的示例相同。 Values of each struct or enum you or someone else creates by default will be moved. 默认情况下,您或其他人创建的每个结构或枚举的值都将被移动。

Another important thing is that you can give every type a destructor , that is, a piece of code which is invoked when the value of this type goes out of scope and destroyed. 另一个重要的事情是你可以给每个类型一个析构函数 ,也就是说,当这个类型的值超出范围并被销毁时调用的一段代码。 For example, destructors associated with Vec or Box will free the corresponding piece of memory. 例如,与VecBox关联的析构函数将释放相应的内存。 Destructors can be declared by implementing Drop trait: 可以通过实现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

There is a way to opt-out of non-copyability by implementing Copy trait which marks the type as automatically copyable - its values will no longer be moved but copied: 有一种方法可以通过实现Copy特征来选择退出不可Copy ,该特征将类型标记为可自动复制 - 其值将不再被移动而是被复制:

#[derive(Copy, Clone)] struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is still available here

The copy is done bytewise - x2 will contain a byte-identical copy of x1 . 副本以字节方式完成 - x2将包含x1的字节相同副本。

Not every type can be made Copy - only those which have Copy interior and do not implement Drop . 不是每种类型都可以Copy - 只有那些具有Copy内部并且不实现 Drop All primitive types (except &mut references but including *const and *mut raw pointers) are Copy in Rust, so each struct which contains only primitives can be made Copy . 所有原始类型(除了&mut引用,但包括*const*mut原始指针)都是Rust中的Copy ,因此每个只包含基元的结构都可以Copy On the other hand, structs like Vec or Box are not Copy - they deliberately do not implement it because bytewise copy of them will lead to double frees because their destructors can be run twice over the same pointer. 另一方面,像VecBox这样的结构不是Copy - 它们故意不实现它,因为它们的字节副本将导致双重释放,因为它们的析构函数可以在同一指针上运行两次。

The Copy bit above is a slight digression on my side, just to give a clearer picture. 上面的Copy位在我身边略显偏离,只是为了给出更清晰的画面。 Ownership in Rust is based on move semantics. Rust中的所有权基于移动语义。 When we say that some value own something, like in " Box<T> owns the given T ", we mean semantic connection between them, not something magical or something which is built into the language. 当我们说某些值拥有某些东西时,比如“ Box<T>拥有给定的T ”,我们指的是它们之间的语义连接,而不是神奇的东西或内置于语言中的东西。 It is just most such values like Vec or Box do not implement Copy and thus moved instead of copied, and they also (optionally) have a destructor which cleans up anything these types may have allocated for them (memory, sockets, files, etc.). VecBox这样的大多数这样的值都没有实现Copy ,因此移动而不是复制,它们也(可选)有一个析构函数来清理这些类型可能为它们分配的任何内容(内存,套接字,文件等)。 )。

Given the above, of course you can write your own "owning" types. 鉴于上述情况,您当然可以编写自己的“拥有”类型。 This is one of the cornerstones of idiomatic Rust, and a lot of code in the standard library and external libraries is written in such way. 这是惯用Rust的基石之一,标准库和外部库中的许多代码都是以这种方式编写的。 For example, some C APIs provide functions for creating and destroying objects. 例如,某些C API提供了创建和销毁对象的功能。 Writing an "owning" wrapper around them is very easy in Rust and it is probably very close to what you're asking for: 在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) }
    }
}

Now you can say that Widget owns some foreign resource represented by *mut WidgetStruct . 现在你可以说Widget 拥有一些由*mut WidgetStruct代表的外部资源。

Here is another example of how a value might own memory and free it when the value is destroyed: 下面是一个值如何拥有内存并在值被销毁时释放它的另一个示例:

extern crate libc;

use libc::{malloc, free, c_void};


struct OwnerOfMemory {
    ptr: *mut c_void
}

impl OwnerOfMemory {
    fn new() -> OwnerOfMemory {
        OwnerOfMemory {
            ptr: unsafe { malloc(128) }
        }
    }
}

impl Drop for OwnerOfMemory {
    fn drop(&mut self) {
        unsafe { free(self.ptr); }
    }
}

fn main() {
    let value = OwnerOfMemory::new();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM