理解 Rust 中的字符串:`String` 与字符串字面量 (`&str`)
发布: (2026年2月21日 GMT+8 16:07)
4 分钟阅读
原文: Dev.to
Source: Dev.to
字符串字面量 (&str)
- 固定的、不可变的 UTF‑8 字节序列,在编译时已知。
- 直接存放在程序的二进制文件中(只读静态内存)。
- 零成本使用:编译器把字节嵌入代码,运行时只在栈或寄存器中创建一个 胖指针(指针 + 长度)。
- 生命周期为
'static—— 整个程序运行期间都有效。
let s: &str = "hello";
"hello"被放置在可执行文件的只读数据段。- 没有堆分配、没有系统调用——只有指针和长度。
String
- 可增长、拥有所有权、可变的 UTF‑8 缓冲区,分配在堆上。
- 可以修改(例如
push_str、push)。 - 在栈上保存三部分:指向堆缓冲区的指针、长度和容量。
let s = String::from("hello");
- 在堆上分配内存,将
"hello"复制进去,并自动管理缓冲区的生命周期(超出作用域时释放)。
对比
| 特性 | &str(字符串字面量) | String |
|---|---|---|
| 可变性 | 不可变 | 可变 |
| 内存位置 | 只读二进制段(静态) | 堆(可增长) |
| 创建方式 | "hello" 或 &"hello" | String::from("hello") |
| 性能 | 访问更快,无分配 | 由于堆分配而较慢 |
| 典型使用场景 | 静态文本,函数参数 | 动态字符串构建 |
存储细节
| 类型 | 存储位置 | 细节 |
|---|---|---|
&str | 只读二进制段 | 指针 + 长度临时位于栈上;字节已嵌入可执行文件中。 |
String | 堆 | 可增长缓冲区;指针、长度和容量存储在栈上。 |
分配与运行时开销
| 类型 | 是否堆分配? | 相对速度 |
|---|---|---|
&'static str | ❌ 无 | 非常快 |
String | ✅ 是 | 较慢(堆操作) |
字符串字面量并不是“分配更快”;它们只是根本避免了运行时的堆分配。
示例:使用字符串字面量
let s = "hello"; // `s` 是一个 `&'static str`
- 字节
"hello"已经是二进制的一部分。 - 在运行时,Rust 只在栈上创建一个小的引用(指针 + 长度)。
示例:创建 String
let s = String::from("hello");
- 在堆上分配内存,复制字节,并将元数据存储在栈上。
- 当
s超出作用域时,缓冲区会自动释放。
总结
&str– 不可变,编译时已知,存储在静态只读内存中,引用时零成本。String– 可变,堆分配,可增长或收缩,带有分配开销。
了解这些差异有助于在特定情境下选择合适的类型:对静态文本和函数参数使用 &str,在需要可变、动态构建的字符串时使用 String。