Rust 字符串
String 与 &str 的分工:拥有型 UTF-8 缓冲 vs 借用切片;索引、拼接与常见陷阱。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust 字符串
这个概念为什么出现
文本处理无处不在,但 Rust 故意把“字符串”拆成多层:
- 字面量与借用视图:
&str - 可增长拥有缓冲:
String - 底层字节:
[u8]/Vec<u8>
还要面对 UTF-8:不能像某些语言一样按“字符下标”廉价随机改。
[!abstract] 一句话理解
&str是 UTF-8 字符串切片(借用);String是堆上可增长的拥有型 UTF-8 缓冲;索引按字节,操作必须落在字符边界。
最小可运行示例
场景:用户中心规范化显示名
注册流把用户输入 " Ada Lovelace " 规范化为小写 trim 后的拥有字符串,并统计字节长度用于存储估算。
// 业务意图:trim + lowercase 得到可存储的 display_name。
// 教学点:&str 输入、String 输出;to_lowercase 产生新 String;len 是字节数。
fn normalize_display_name(raw: &str) -> String {
let trimmed = raw.trim(); // &str 切片,仍借用 raw
trimmed.to_lowercase() // 得到拥有的 String
}
fn main() {
let input = " Ada Lovelace ";
let name = normalize_display_name(input);
println!("display_name={name}");
println!("byte_len={}", name.len()); // UTF-8 字节长度
println!("chars={}", name.chars().count());
}
建议运行:
cargo run
期望输出:
display_name=ada lovelace
byte_len=12
chars=12
结合场景再看三个关注点
- API 收
&str、返回String:调用方用字面量或已有String都行。 len()是字节:含中文时字节数 ≠ 字符数。- 不要
s[0]取字符:String/str不支持按usize直接索引字符。
核心概念与准确模型
| 类型 | 拥有? | 可变增长? | 典型来源 |
|---|---|---|---|
&str | 否 | 否(视图) | 字面量、String 借用 |
String | 是 | 是 | String::from、to_string、format! |
&[u8] | 否 | 否 | 原始字节 |
常用构造:
let s = String::from("hi");
let t = "hi".to_string();
let u = format!("user={id}", id=7);
拼接:
let mut s = String::from("hello");
s.push_str(", world");
s.push('!');
let both = s + "!!"; // + 会吃掉左侧 String 所有权
遍历:chars()、bytes()、或按 split_whitespace 等。
设计动机
- UTF-8 默认正确处理全球文本
- 区分借用/拥有,避免隐式拷贝
- 强制处理编码边界,减少半吊子截断
边界情况与反直觉行为
- 中文等字符多字节:
&s[0..1]可能 panic +运算符对String的所有权特殊OsString/Path/CString是另一类字符串边界(OS/FFI)
常见误区
[!warning] 常见误区:用下标取“第 n 个字符” 正确做法:
chars().nth(n)(O(n))或用 crate 处理字形簇。
[!warning] 常见误区:把
String与str当成无关类型str是 DST;String可Deref到str,故很多方法在两者上都能调。
工程实践
- 函数参数优先
&str - 需要拥有再
String - 日志/格式化用
format!或write! - 性能敏感路径避免无谓分配
本节总结
&str借用,String拥有- UTF-8 字节索引要落在边界
- 文本 API 设计先想清所有权
自测题
- 为什么
s[0]对String不成立? fn f(s: String)与fn f(s: &str)的调用体验差在哪?
参考答案
- 字符串按 UTF-8 编码,单字节下标不一定是字符边界,且类型未实现
Index<usize>取 char。 - 收
String会强制调用方交出或 clone;&str更通用。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Storing UTF-8 Encoded Text with Strings | 官方书 | String |
| std::string::String | 标准库 | API |
| std::str | 标准库 | &str 方法 |