Rust String 与 &str
更新时间:2026-09-20。Rust 字符串是新手高频报错来源:它分「拥有所有权的
String」和「借用的切片&str」两层。底层内存布局可对照 Vec/String 内存布局与扩容。
一、核心区别
String | &str | |
|---|---|---|
| 所有权 | 拥有堆字节,离开作用域自动释放 | 借用,不负责释放 |
| 可变性 | mut 后可增长/修改 | 不可变视图 |
| 底层 | 堆上 UTF-8 字节(指针+len+cap) | 胖指针(数据指针 + 长度) |
| 来源 | String::from、.to_string()、format! | 字面量、切片、&String 强转 |
| 寿命 | 自管 | 受借出方约束(字面量是 'static) |
rust
let s: String = String::from("hello"); // 堆上、可增长
let lit: &str = "hello"; // 字面量:&'static str,编入二进制只读区
let view: &str = &s; // 从 String 借出切片二、String 的增长与容量
rust
let mut s = String::new();
s.push_str("hello");
s.push('!');
s += " world";
let combined = format!("{} {}", s, 42); // 不取得参数所有权
println!("len={} cap={}", s.len(), s.capacity());和 Vec<u8> 一样,容量不够时按策略重新分配、可能整体搬迁,循环里大量拼接可用 with_capacity 预留,或用 write! 到 String 减少分配(呼应内存布局与扩容)。
三、相互转换与参数选型
rust
// String -> &str
let s = String::from("hi");
let a: &str = &s; // 自动解引用(Deref),等价 s.as_str()
let b: &str = s.as_str();
// &str -> String
let t1 = "hi".to_string();
let t2 = String::from("hi");
let t3 = format!("{}", "hi");
// 子串是切片(字节边界内)
let sub = &s[0..2];函数参数优先收 &str:它既能接字面量,也能接 &String(自动 Deref),最通用;只有需要取得所有权、存储或修改时才用 String。
rust
fn greet(name: &str) { println!("hi {name}"); }
greet("alice"); // &str
greet(&String::from("bob")); // &String 自动解成 &str四、为什么不能按索引取字符
Rust 字符串是 UTF-8 字节:一个汉字占 3 字节,s[0] 无法保证落在字符边界,因此直接索引编译不过。
rust
let s = "你好";
// let c = s[0]; // 编译错误
assert_eq!(s.len(), 6); // 字节数,不是字符数
assert_eq!(s.chars().count(), 2); // 字符数(char 是 Unicode 标量值)
for ch in s.chars() { /* 按字符 */ }
for b in s.bytes() { /* 按字节 */ }字节切片必须落在 UTF-8 边界,否则运行时 panic;需要随机访问按「字符」的数据可先 chars().collect::<Vec<char>>()。
五、常见坑
- 返回局部
&str:函数里String出作用域就释放,返回它的切片会悬垂,应直接返回String(生命周期规则见生命周期)。 - 参数用
&String:比&str更受限且无收益,统一写&str。 len()当字符数:它是 UTF-8 字节数,中文场景用chars().count()。push与push_str混用:push接单个char,push_str接字符串片段。- 频繁拼接造分配:循环里
s += part可能反复扩容,预留容量或改用write!/join。
总结
Rust 的 String 是拥有堆缓冲、可变可增长、离开作用域自动释放的 UTF-8 字节串(指针+len+cap),&str 是由指针和长度构成的不可变借用切片,字符串字面量是编进只读数据的 &'static str;二者经 as_str/&String(Deref)与 to_string/String::from 互转,函数参数优先用最通用的 &str;字符串按 UTF-8 编码、不能按整数索引取字符,len 是字节数、要数字符用 chars,且不要返回局部 String 的悬垂切片。