在 Rust 中,切片和引用有什么关系?

5
我完全是Rust的新手(就是昨天才开始学习),正在阅读《Rust编程语言》。我在第4.2章(引用和借用)/第4.3章(切片类型)有一些困惑,因此我试图在继续学习之前巩固对引用的初步理解。我是一名经验丰富的程序员,主要背景是C++(我熟悉多种编程语言,但C++是我最熟悉的语言)。
请看下面的Rust代码:
let string_obj: String = String::from("My String");
let string_ref: &String = &string_obj;
let string_slice: &str = &string_obj[1..=5];

根据我的理解,从第一行开始,string_obj 是一个存储在栈上的类型为String 的对象,它包含三个字段:(1) 指向堆上分配的编码为 UTF-8 的文本"My String"的指针;(2) 值为9的长度字段;(3) 值 >= 9 的容量字段。这很简单明了。
从第二行开始,string_ref 是对存储在栈上的 String 对象的不可变引用,它包含一个字段 - 指向 string_obj 的指针。这让我相信(不考虑所有权规则、语义和其他尚未了解的引用问题),引用本质上是对其他对象的指针。同样也很简单。
正是第三行让我有些困惑。 根据文档, string_slice 似乎是一个存储在栈上的&str类型的对象,并且包含两个字段:1)指向与 string_obj 关联的文本“My String”中的“y Str”的指针。2)值为5的长度字段。
但至少从表面上看,&str 类型按定义是指向类型为 str 的对象的不可变引用。那么我的问题如下:
  1. str 到底是什么,它在内存中是怎样表示的?
  2. 一个引用类型的& amp; str - 我原以为它只是一个指针 - 如何包含两个字段(一个指针和一个长度)?
  3. Rust 怎么知道在构造引用时要创建多少个字段?(因此程序员怎么知道呢?)
1个回答

7
切片是 Rust 中的原始类型,这意味着它们不一定遵循其他类型的语法规则。在这种情况下,str 和 &str 是特殊的,并且会受到一些魔法的影响。
类型 str 并不存在,因为您无法拥有其内容的切片。要求我们将此类型拼写为 "&str" 的原因是语法上的:& 提醒我们正在使用从其他地方借来的数据,并且需要指定生命周期,例如:
fn example<'a>(x: &String, y: &'a String) -> &'a str {
    &y[..]
}

这也是必要的,以便我们可以区分不可变借用的字符串切片(&str)和可变借用的字符串切片(&mut str)。 (尽管后者在其有用性方面受到一定限制,因此您不经常看到它们。)
请注意,相同的事情也适用于数组切片。 我们有像[u8; 16]这样的数组和像&[u8]这样的切片,但我们实际上并不直接与[u8]交互。 在这里,可变变体(&mut [u8])比字符串切片更有用。
引用块:

究竟什么是str,它在内存中如何表示?

根据上述内容,str本质上并不存在。但是,&str的布局就像您所怀疑的那样——一个指针和一个长度。
(str 是切片引用的实际字符,是所谓的 dynamically-sized type。在一般情况下,&T 不能没有 T 存在。在这种情况下,有点反过来,因为 str 并不存在,没有 &str 切片。)

&str - 一个引用类型,我以为它只是一个指针 - 如何包含两个字段(指针和长度)?

作为原始类型,它是编译器处理的特殊情况。

Rust 在构造引用时如何知道一般情况下要创建什么 / 多少个字段? (因此程序员如何知道?)

如果它是非切片引用,则它是指针或什么都不是(如果引用本身可以被优化掉)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接