返回文章列表

文章

&'static str、&str、String等的区别

目录
  1. 下面从内存分配、所有权与借用、生命周期和常见使用场景几个维度来对比 &'static str、&str、String。
  2. 1. 类型概念与内存分配
  3. 2. 所有权与借用
  4. 3. 生命周期
  5. 4. 使用场景对比
  6. 5. 性能与内存考量
  7. 6. 小结

下面从内存分配所有权与借用生命周期常见使用场景几个维度来对比 &'static str&strString#

1. 类型概念与内存分配#

类型内存位置可变性所有权
`&'static str`二进制文件区(静态区)不可变不拥有所有权(指向常量)
`&str`可在栈或堆不可变不拥有所有权(借用)
`String`可变拥有所有权
  • &str
    • 本质是 (ptr: *const u8, len: usize) 的字符串切片。
    • 不持有内存,只是对已分配字符串的借用。
  • &'static str
    • &str 的子类型,生命周期标注为 'static
    • 通常来自编译时的字符串字面量,例如 let s: &'static str = "hello";
    • 字符串内容编译进可执行文件,整个程序运行期间都有效。
  • String
    • 堆上分配可增长的 UTF‑8 字符串缓冲区。
    • 结构体内部包含指向堆内存的指针、长度和容量。
    • 拥有其所指向的数据,超出作用域时会自动释放。

2. 所有权与借用#

let s1: String        = String::from("foo");      // 拥有所有权
let s2: &str          = &s1;                     // 不可变借用
let s3: &'static str  = "bar";                   // 静态借用,永不过期

  • String** → **&str 可以随时借用整个字符串的只读视图:

fn print_str(s: &str) { println!("{}", s); } print_str(&s1); // 借用而非转移所有权

```
  • &str** → **String 需要复制/克隆:

let owned: String = s2.to_string(); let owned2: String = String::from(s2);

```
  • &'static str 永不失效,可安全地在全局存储和多线程场景中传递,不需担心借用过期。

3. 生命周期#

  • &'static str 生命周期是整个程序运行期。适合 “常量文本” 或全局消息、日志前缀等。
  • &str 生命周期受限于所借用值的作用域。借用期间不能修改原值,也不能让原值先于借用结束而析构。
  • String 生命周期由其所有者(变量)决定,到作用域尾自动 drop,安全管理堆内存。

4. 使用场景对比#

场景推荐类型说明
编译时已知的不变文本`&'static str`零开销、永不过期,如程序标题、固定消息、日志标签。
接收外部输入(文件/网络/用户)`String`大小未知、需要 grow/shrink、需要所有权便于传递和修改。
函数参数只需读取字符串`&str`通用且灵活,既能接收 `String` 也能接收字符串字面量。
需要拼接、多次修改或动态构造文本`String`支持 `.push_str()`, `.insert()`, `.replace_range()` 等可变操作。
暂时借用某段连续内存做切片`&str`从一长串文本中取子串无需复制,如 `full[5..10]`。
存储到结构体字段,需跨函数传递`String` 或 `&'static str`动态文本用 `String`,常量文本可用 `&'static str`,切勿用临时 `&str`。

5. 性能与内存考量#

  • 零拷贝借用(&str/&'static str
    • 只有指针和长度的开销。
    • 读性能最高,没有堆分配或复制。
  • 堆分配(String
    • 首次分配需申请堆内存;
    • 扩容时可能重新分配并复制已有数据;
    • 适合可变文本,但要尽量复用同一个 String(避免反复 to_string())。

6. 小结#

  • &'static str零开销常量,全程有效,适合程序静态文本。
  • &str灵活借用,只读通用接口,适合作为函数参数。
  • String可变拥有,支持动态构造与修改,适合可变/外部文本。 通过合理选择,你可以在 性能(零拷贝)和 灵活性(动态拼接与所有权)之间取得最佳平衡。