考虑这个简单的代码
fn main () {
let mut s: &str = "hello";
s = "hey";
println! ("{}", s);
}
我了解到字符串文字本质上是不可变的。我同意这一点,因为这里的变量“s”指的是值“hello”的第一个字符的地址。所以基本上它是一个指针。现在,如果我将 s 的值更改为“hey”,这并不是在内存中的某个位置“就地”替换值“hello”,但它本质上是创建一个新的地址位置,将值“hey”存储在它并获取该地址并将其绑定到 s。这个很好理解。
但是我感到困惑的是,由于必须在编译时知道变量的大小才能将它们放置在堆栈上,那么字符串文字也存储在堆栈上还是堆上?它们可能存储在堆栈上作为硬编码值。但如果是这样只能在运行时确定的东西呢?
fn main () {
let mut user_input = String::new();
let stdin = io::stdin(); // We get user input whose size we can't predict
stdin.read_line(&mut user_input);
let ab = user_input.as_str(); // taking the value on heap and turning it to string literal and creating a new reference pointer 'ab' on the stack
println!("input {}, {} ", user_input, ab);
}
上面的字符串文字值“ab”存储在哪里?堆栈还是堆?
那么字符串文字也存储在堆栈中还是堆中?
都不是。字符串文字通常存储在生成的可执行文件的“rodata”(只读数据)段中。
但是如果是这样只能在运行时确定的东西怎么办?
根据定义,字符串文字不是在运行时确定的。
上面的字符串文字值“ab”存储在哪里?堆栈还是堆?
字符串slice(
&str
)不是字符串文字,它是指向非拥有字符串的指针。当您写入 user_input.as_str()
时,您只会获得第二个指向存储在 user_input
中的字符串的指针。
字符串文字的类型为
&'static str
。注意'static
部分。它们被放置在二进制文件的只读存储器中。它不是堆栈也不是堆。您的操作系统在启动进程时分配此内存。这与您编写的内容相同:
static FOO: usize = 42;
Rust 会将其放置在二进制文件的只读部分中。并且您可以获得对它的
'static
引用,因为只要您的进程存在,该内存就始终有效。
至于字符串文字的大小,编译器显然知道它的大小,因此它知道为它们保留多少内存。
&str
实际上被称为宽指针或胖指针,因为它有两个字(指针)的大小。它保存一个指向内存的指针,其中字符串文字(或任何其他字符串切片)开始及其长度。您可以将其视为(*const u8, usize)
。因此字符串切片可以指向包含字符串的any内存。它是堆栈、堆还是二进制文件中的其他数据段并不重要。
您可以阅读 The Rust Book 中的关于切片的章节,以更好地理解这个概念。