Rust 中 String 和&str 在内存布局上有什么本质区别

文章导读
Rust 中 String 和&str 的本质区别在于所有权和内存布局:String 拥有堆上数据的所有权,栈上存储指针、长度和容量三个字段;&str 是不变引用,栈上仅存储指针和长度两个字段,不拥有数据所有权。
📋 目录
  1. 快速处理思路
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

Rust 中 String 和&str 的本质区别在于所有权和内存布局:String 拥有堆上数据的所有权,栈上存储指针、长度和容量三个字段;&str 是不变引用,栈上仅存储指针和长度两个字段,不拥有数据所有权。

先说结论:String 是拥有所有权的可增长堆字符串,&str 是借用数据的不可变视图,两者在 64 位系统上的栈内存占用分别为 24 字节和 16 字节。

  • 适合:需要修改内容或拥有所有权时使用 String,仅读取或传递参数时使用&str。
  • 重点看:String 包含容量字段支持扩容,&str 无容量字段仅指向现有内存。
  • 别忽略:&str 的生命周期依赖所引用数据的存活时间,返回&str 需确保数据不失效。

快速处理思路

判断使用 String 还是&str 主要依据是否需要修改内容和是否拥有所有权。如果需要构建、拼接或修改字符串,选择 String;如果仅作为函数参数传递或读取静态文本,优先使用&str 以减少内存分配。验证方法是通过 std::mem::size_of_val 检查栈上大小,确认 64 位系统下 String 为 24 字节,&str 为 16 字节。

为什么会这样

根本原因是所有权模型决定了内存管理方式的不同。String 内部封装了 Vec<u8>,在堆上分配连续内存存储 UTF-8 字节,栈上保存控制结构以便管理释放;&str 则是胖指针结构,仅记录数据起始地址和长度,不管理内存生命周期。这种设计让 String 适合动态场景,&str 适合零拷贝读取。

分步处理

第一步是确认数据是否需要修改,若需 push 或拼接必须用 String。第二步是检查函数签名,参数类型优先定义为&str 以兼容 String 和字面量。第三步是验证内存布局,编写测试代码打印 size_of_val 结果。第四步是检查生命周期,确保返回的&str 不引用局部 String 变量。

use std::mem;\n\nfn main() {\n    let s = String::from("hello");\n    let slice: &str = "world";\n    println!("String 大小:{} 字节", mem::size_of_val(&s));\n    println!("&str 大小:{} 字节", mem::size_of_val(&slice));\n}

怎么验证是否生效

运行上述代码后观察控制台输出,64 位系统下应显示 String 大小为 24 字节,&str 大小为 16 字节。若数值不符,检查编译器目标架构是否为 64 位。此外可通过打印 capacity 字段验证 String 是否有扩容空间,&str 访问 capacity 方法会报错。

Rust 中 String 和&str 在内存布局上有什么本质区别

常见坑

第一个坑是函数返回局部 String 的&str 引用,会导致悬垂指针,编译期会报错。第二个坑是误以为&str 可以修改内容,尝试修改会触发编译错误。第三个坑是索引操作,String 和&str 均不支持按字符索引,只能按字节切片,越界会 panic。第四个坑是性能误区,频繁将&str 转为 String 会导致堆分配开销增加。

常见问题

String 和&str 能直接互换吗?

不能直接互换,需要通过方法转换。String 转&str 使用解引用或切片操作,&str 转 String 使用 to_string 或 String::from。

为什么函数参数推荐用&str?

因为&str 接受 String 引用和字符串字面量,兼容性更好且避免不必要的堆内存分配和所有权转移。

String 的容量字段有什么作用?

容量字段记录已分配的堆内存大小,允许字符串在不重新分配的情况下增长,减少扩容时的性能开销。

参考来源

  • String 与 &str:从内存到性能的 Rust 字符串魔法 - 腾讯云开发者社区
  • 深入理解 Rust 的 String 与 &str:内部实现与实践思考
  • Rust 知识点——String 与&str 的内部实现差异
  • 深入解析 Rust 中的 String 与 &str:从内存布局到性能优化的全面对比
  • Rust 深度剖析:String 与 &str 的内存布局与实现差异
  • rust 中,&str 和 String 有什么区别和联系?
  • Rust 初学 之 &str 和 String 的区别 (附 胖指针 & 内存说明)
  • Rust 之 String 与&str 的内部实现差异的理解
  • rust 字符与字符串:String 和&str 的异同