Rust 我不知道';我不理解切片和引用之间的区别

Rust 我不知道';我不理解切片和引用之间的区别,rust,reference,slice,terminology,Rust,Reference,Slice,Terminology,我不明白切片和引用之间的区别。&String和&str之间有什么区别?我在网上读到一些东西,说引用是一个瘦指针,而slice是一个胖指针,但我不知道,似乎也找不到这两个词的意思。我知道切片可以强制成为引用,但它是如何做到的?什么是Deref特征?在Rust中,切片是长度不同的同质类型数据的连续块 这是什么意思 [u8]是一个切片。在内存中,这是一个u8s块。切片本身就是数据。但是,很多时候,人们把和[u8]看作一个片段。和[u8]是指向该数据块的指针。该指针包含两个内容:指向数据本身的指针和数

我不明白切片和引用之间的区别。
&String
&str
之间有什么区别?我在网上读到一些东西,说引用是一个瘦指针,而slice是一个胖指针,但我不知道,似乎也找不到这两个词的意思。我知道切片可以强制成为引用,但它是如何做到的?什么是Deref特征?

在Rust中,切片是长度不同的同质类型数据的连续块

这是什么意思

  • [u8]
    是一个切片。在内存中,这是一个
    u8
    s块。切片本身就是数据。但是,很多时候,人们把
    和[u8]
    看作一个片段。
    和[u8]
    是指向该数据块的指针。该指针包含两个内容:指向数据本身的指针和数据的长度。由于它包含两个内容,因此称为胖指针。
    &u8
    也是一个参考(在本例中也可以被视为一个指针*),但我们已经知道,无论它指向什么,都将是一个
    u8
    。因此,它是一个细指针,因为它只有一个元素

    我们保证
    [u8]
    中的所有数据都属于
    u8
    类型

    由于您的
    [u8]
    只是定义为
    u8
    类型的连续内存块,因此没有编译时定义它的大小。因此,我们需要将其长度存储在指向它的指针中。我们也不能将其放在堆栈上(这意味着:我们不能有一个仅是
    [u8]
    **的局部变量)

扩展:

  • A
    [T]
    T
    s的一部分。对于任何给定的
    T
    ,只要
    T
    本身是一个大小合适的类型***,我们就可以想象一个类型
    [T]
  • str
    是字符串的一部分。它保证是有效的UTF-8文本,这就是它与
    [u8]
    的区别所在。Rust可能已经放弃了有效的UTF-8担保,只是将
    str
    中的所有其他内容定义为
    [u8]
    的一部分
嗯,由于您不能在本地拥有切片,您可能想知道我们如何创建切片

答案是,我们将数据放入已知大小的东西中,然后从中借用切片

例如:

let my_array: [u32; 3] = [1, 2, 3];
我们可以将
my_数组
切成
[u32]
如下:

let my_slice: [u32] = my_array[..];
但由于我们不能拥有大小未知的局部变量,因此必须将其置于引用下:

let my_slice: &[u32] = &my_array[..];
切片的意义在于,无论数据来自何处,它都是处理连续数据块的一种非常灵活的方法(限制生命周期)。我可以很容易地制作
我的_数组
一个
Vec
,这是堆分配的,它仍然可以工作

&String和&str之间有什么区别

&String
是对整个字符串对象的引用。Rust中的字符串对象本质上是一个
Vec
Vec
包含指向它“包含”的数据的指针,因此您的
&String
可以被认为是
&str
。这就是为什么我们可以做以下任何一项:

let my_string: String = "Abc".to_string();

let my_str: &str = &my_string[..]; // As explained previously
// OR
let my_str: &str = &*my_string;
对这一点的解释让我想到你的最后一个问题:

德里夫的特点是什么

Deref
特征是一种描述解引用(
*
)运算符的特征。正如您在上面所看到的,我能够执行
*我的字符串
。这是因为
String
实现了
Deref
,它允许您取消对
字符串的引用。类似地,我可以将
Vec
解引用为
[T]

但是,请注意,
Deref
特征用于的地方比使用
*
的地方多:

let my_string: String = "Abc".to_string();

let my_str: &str = &my_string;
如果我尝试将类型为
&T
的值分配到类型为
&U
的位置,则Rust将尝试取消对我的
T
的引用,次数与获得
U
所需次数相同,同时至少保留一个引用。类似地,如果我有一个
&&&&&&&&&&&&T
,并且我尝试将它分配给
&&&&&&&&&&U
,它仍然可以工作

这称为解除强制:自动将
&T
转换为
&U
,其中一定量的
*T
将导致
U


  • *:原始指针
    *const T
    *mut T T
    与引用的大小相同,但被编译器视为不透明。编译器不能保证原始指针后面的内容,甚至不能保证它们正确对齐。因此,取消引用是不安全的。但是由于
    Deref
    特性定义了一个安全的
    Deref
    方法,因此取消对原始指针的引用是特殊的,也不会自动完成
  • **:这也包括其他动态大小的类型,如trait对象和
    extern type
    s。这还包括
    struct
    s,其中还包含一个动态大小的类型作为其最后一个成员,尽管这些类型很难正确构造,但将来使用
    强制化
    特性将变得更容易。通过使用允许使用动态大小局部变量的
    unsized_locals
    nightly功能,可以使所有这些(外部类型除外)无效
  • ***:Sized类型是编译时已知大小的所有类型。你可以一般地识别它们;给定类型
    T
    T
    的大小在编译时已知,如果
    T:Sized
    。如果
    T:?Sized
    ,则其大小可能在编译时未知(
    T:?Sized
    是调用方最灵活的要求,因为它接受任何内容)。因为切片需要da