Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pointers Rust如何知道哪些类型拥有资源?_Pointers_Heap_Rust_Ownership - Fatal编程技术网

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

Pointers Rust如何知道哪些类型拥有资源?,pointers,heap,rust,ownership,Pointers,Heap,Rust,Ownership,当有一个指向某个堆分配内存的框指针时,我假设Rust具有所有权的“硬编码”知识,因此当通过调用某个函数来转移所有权时,资源会被移动,函数中的参数就是新的所有者 然而,例如,向量是如何发生这种情况的?它们也“拥有”自己的资源,所有权机制也适用于框指针——但它们是存储在变量本身中的常规值,而不是指针。Rust(知道)如何在这种情况下应用所有权机制 我可以自己制作拥有资源的类型吗?tl;dr:Rust中的“拥有”类型并不是什么神奇的东西,它们肯定不是硬编码到编译器或语言中的。它们只是以某种方式编写的类

当有一个指向某个堆分配内存的框指针时,我假设Rust具有所有权的“硬编码”知识,因此当通过调用某个函数来转移所有权时,资源会被移动,函数中的参数就是新的所有者

然而,例如,向量是如何发生这种情况的?它们也“拥有”自己的资源,所有权机制也适用于框指针——但它们是存储在变量本身中的常规值,而不是指针。Rust(知道)如何在这种情况下应用所有权机制

我可以自己制作拥有资源的类型吗?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
将值传递给函数时也会发生同样的情况:

fn do_something(x: X) {}

let x1 = X(12);
do_something(x1);
// x1 is no longer accessible here
请注意,这里绝对没有什么神奇之处——只是默认情况下,每种类型的每个值的行为都与上述示例中的相同。默认情况下,您或其他人创建的每个结构或枚举的值都将被移动

另一件重要的事情是,您可以为每个类型提供一个析构函数,即当该类型的值超出范围并被销毁时调用的一段代码。例如,与
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
trait选择不可复制,该特性将类型标记为自动可复制-其值将不再移动,而是复制:

#[derive(Copy, Clone)] struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is still available here
复制是按字节进行的-
x2
将包含与
x1
相同的字节副本

并非每种类型都可以进行
复制
——只有那些具有
复制
内部且未实现
拖放的类型。所有基元类型(除了
&mut
引用,但包括
*const
*mut
原始指针)都是
Copy
生锈的,因此每个只包含基元的结构都可以制作成
Copy
。另一方面,像
Vec
Box
这样的结构不是
Copy
——它们故意不实现它,因为它们的字节复制将导致双重释放,因为它们的析构函数可以在同一指针上运行两次

上面的
Copy
一点在我这边是有点离题的,只是为了让画面更清晰。Rust中的所有权基于移动语义。当我们说某些值拥有某些东西时,比如“
Box
拥有给定的
T
”,我们指的是它们之间的语义联系,而不是神奇的东西或语言中固有的东西。只是像
Vec
Box
这样的大多数值都没有实现
Copy
,因此被移动而不是复制,而且它们还(可选)有一个析构函数,可以清除这些类型可能分配给它们的任何内容(内存、套接字、文件等)

鉴于上述情况,您当然可以编写自己的“拥有”类型。这是惯用Rust的基石之一,标准库和外部库中的许多代码都是以这种方式编写的。例如,一些C API提供了创建和销毁对象的函数。在它们周围写一个“拥有”的包装很容易生锈,而且可能非常接近你的要求:

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) }
    }
}

现在您可以说,
小部件
拥有一些由
*mut WidgetStruct

表示的外部资源。下面是另一个示例,说明值如何拥有内存,并在值被销毁时释放内存:

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();
}

我不确定我是否理解你的问题,但是当你把一个值放到一个向量中时,这个值就属于这个向量了。我想如果你能提供一个你所问问题的代码示例会很有帮助。我现在没有时间写完整的答案,我只想说,
Box
不是特殊的或硬编码的。(嗯,目前有些方面是,但这些方面都与这个问题无关,它们只是硬编码的,因为用纯库代码表达这些内容的语言功能还没有完成。)Box的所有权与Vec的所有权完全相同。@Adrian但是当你把一个值放入一个向量中时,这个值就被向量所拥有。“AFAIK价值观不是所有的,而是资源。我不是在问向量中的数据,我是在问向量变量拥有内存这一事实,就像盒子一样——但它不是盒子。我基本上只是想问一下Rust的内部结构,即所有权适用于哪些结构,以及如何确定它。@delnan我认为所有权必须在语言中“烘焙”出来?如果您没有时间解释这一点,您是否有这样的链接?当您创建一个新向量(
Vec::new
)或推送到一个向量时,内存由该向量分配,例如在上
Vec
实现了
Drop
,这使得在上发生的向量销毁时可以释放内存。请注意,基元类型集还包括原始指针
*mut
*const
,它们用于实现
Box
Vec
以及其他容器类型。如果不使用
下拉菜单
impl,
Vec
可能完全是
Copy
——这将是
不安全的
,语义错误。因为它经常会让人绊倒,请注意,移动和复制都是id