[英]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. 例如,与
Vec
或Box
关联的析构函数将释放相应的内存。 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. 另一方面,像
Vec
或Box
这样的结构不是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.). 像
Vec
或Box
这样的大多数这样的值都没有实现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.