我对 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)a指向文本“My String”的指针,分配在堆上,以 UTF-8 编码; (2) 一个值为9的长度字段; (3) 一个值 >= 9 的容量字段。这很简单。
从第二行开始,string_ref
是对 String
对象的不可变引用,也存储在堆栈中,它包含一个字段 - 指向 的指针字符串对象
。这让我相信(抛开所有权规则、语义和其他我尚未了解的有关引用的内容),引用本质上是指向其他对象的指针。同样,非常简单。
第三行让我有些头疼。从文档中可以看出,string_slice
是存储在堆栈中的 &str
类型的对象,包含两个字段:1) 指向文本“y”的指针Str”,在与 string_obj
关联的文本“My String”中。 2) 一个值为 5 的长度字段。
但是,至少从表面上看,&str
类型根据定义是对类型 str
对象的不可变引用。所以我的问题如下:
- 究竟是什么
str
,它在内存中是如何表示的? &str
- 一个引用类型,我认为只是一个指针 - 如何包含两个字段(一个指针和一个长度) ?- 在构建引用时,Rust 通常如何知道要创建什么/多少字段? (因此程序员怎么知道的?)
最佳答案
切片是 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]
) 比字符串切片更有用。
What exactly is an
str
, and how is it represented in memory?
如上所述,str
本身并不真正存在。 &str
的布局正如您所怀疑的那样——一个指针和一个长度。
(str
是 slice 引用的实际字符,也就是所谓的 dynamically-sized type 。在一般情况下, &T
不能存在没有要引用的 T
。在这种情况下,它有点倒退,因为没有 &str
切片,str
就不存在。)
How does
&str
- a reference type, which I thought was simply a pointer - contain TWO fields (a pointer AND a length)?
作为原语,它是编译器处理的一种特殊情况。
How does Rust know in general what / how many fields to create when constructing a reference? (and consequently how does the programmer know?)
如果它是一个非切片引用,那么它要么是一个指针,要么什么都不是(如果引用本身可以被优化掉)。
关于string - Rust 中的切片和引用之间的关系是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71516959/