gpt4 book ai didi

rust - 我不了解切片和引用(使用rust )之间的区别

转载 作者:行者123 更新时间:2023-12-03 11:25:32 26 4
gpt4 key购买 nike

我是 rust 的初学者。我不了解 rust 切片和引用之间的区别。 &String和&str有什么区别?我在网上阅读了一些东西,说引用是一个瘦指针,而切片是一个胖指针,但我不知道,似乎也找不到这两个意思。我也知道切片可以强制转换为引用,但是它是如何做到的呢?什么是deref特性?

最佳答案

在Rust中,切片是长度可变的同类数据的连续块。

这是什么意思?

  • [u8]是一个切片。在内存中,这是u8的块。切片本身就是数据。尽管很多时候,人们都将&[u8]称为切片。 &[u8]是指向该数据块的指针。该指针包含两件事:指向数据本身的指针和数据的长度。由于它包含两件事,因此称为胖指针。 &u8也是一个引用(在这种情况下,也可以视为指针 * ),但是我们已经知道,它指向的任何内容都将是一个u8。因此,它是一个瘦指针,因为它只有一个元素。

    您可以确保[u8]中的所有数据均为u8类型。

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

  • 扩展中:
  • [T]T的一部分。对于任何给定的T,只要T本身是大小合适的 *** 类型,我们就可以想象出[T]类型。
  • str是字符串的一部分。保证它是有效的UTF-8文本,这就是将其与[u8]分开的所有内容。 Rust可能已经放弃了有效的UTF-8保证,而只是将str中的其他所有内容定义为[u8]的一部分。

  • 好吧,由于您无法在本地拥有切片 **** ,您可能想知道我们如何创建切片。

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

    举个例子:
    let my_array: [u32; 3] = [1, 2, 3];

    我们可以像这样将 my_array切片为 [u32]:
    let my_slice: [u32] = my_array[..];

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

    切片的意义在于,无论数据来自何处,它都是一种非常灵活的(限制生命周期)处理连续数据块的方法。我可以很容易地将 my_array变成 Vec<u8>,它是堆分配的,并且仍然可以使用。

    What is the difference between &String and &str?


    &String是对整个字符串对象的引用。 Rust中的字符串对象本质上是一个 Vec<u8>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;

    对此的解释将我带到您的最后一个问题:

    What is the deref trait?


    Deref特性,是描述取消引用( *)运算符的特性。如您在上面看到的,我能够执行 *my_string。这是因为 String实现了 Deref,它允许您取消引用 String。同样,我可以将 Vec<T>取消引用到 [T]中。

    但是请注意,除了使用 Deref之外, *特性还用于更多的地方:
    let my_string: String = "Abc".to_string();

    let my_str: &str = &my_string;

    如果我尝试将 &T类型的值分配给 &U类型的位置,那么Rust将尝试取消引用我的 T,这与获取 U所需的次数一样多,同时仍保留至少一个引用。同样,如果我有一个 &&&&....&&&&T,并且尝试将其分配给 &&&&....&&&&U,它将仍然有效。

    称为deref强制:自动将 &T转换为 &U,其中一定数量的 *T将产生 U

  • *:原始指针*const T*mut T与引用的大小相同,但被编译器视为不透明。编译器不保证原始指针背后的内容,也不保证它们正确对齐。因此,取消引用是不安全的。但是,由于Deref特性定义了一种安全的deref方法,因此取消引用原始指针是很特殊的,并且也不会自动完成。
  • **:这也包括其他动态大小的类型,例如特征对象和extern type。这也包括struct,它也包含动态大小类型作为其最后一个成员,尽管很难正确构造它们,但是将来随着CoerceUnsized特性的出现,它会变得更加容易。可以使用extern type nightly功能使所有这些功能(unsized_locals除外)都无效,该功能允许使用一些动态大小的局部变量。
  • ***:大小类型是在编译时已知大小的所有类型。您可以通用地识别它们;给定类型T,如果是T,则在编译时就知道T: Sized的大小。如果是T: ?Sized,则在编译时可能不知道其大小(由于T: ?Sized接受任何内容,因此它是调用方最灵活的要求)。由于切片需要内部的数据是连续的,并且大小和类型是相同的,因此切片,数组或!Sized中不能包含动态大小的类型(或Vec<T>),并且不能维护O(1)索引。尽管Rust可能会编写特殊的代码来索引到一组动态大小的类型中,但目前还没有。
  • ****:您实际上可以拥有一个切片,它只需要在拥有它的指针下即可。例如,这可以是Box<[T]>Rc<[T]>。这些将自行释放分片(删除时为Box,而删除了Rc的所有强引用和弱引用时,则为Rc(当删除所有强引用时,将调用值的析构函数,但是直到所有弱引用也消失了。))。
  • 关于rust - 我不了解切片和引用(使用rust )之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61151041/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com