讲解
Vec 是动态数组:堆上存储、长度可变、元素同类型,是 Rust 里使用频率最高的集合。创建用 Vec::new() 或 vec![1, 2, 3] 宏;尾部追加 push(摊还 O(1)),弹出 pop 返回 Option;读取分两种风格:v[i] 下标直取(越界 panic,适合你确信在界内)和 v.get(i)(越界得 None,安全首选)。遍历 for x in &v 拿引用、for x in &mut v 改元素、for x in v 消耗 Vec 拿所有权。
String 本质上是 Vec 包了一层「保证是合法 UTF-8」的壳。创建用 String::new()、String::from("...")、"...".to_string();追加用 push_str(&str) 和 push(char);拼接推荐 format!("{a}{b}") 宏——注意 + 运算符会拿走左操作数的所有权(let s3 = s1 + &s2 之后 s1 失效),链式拼接时 format! 更省心。
UTF-8 带来一个反直觉点:Rust 不允许 s[0] 这样按下标取字符。因为一个「字符」可能占 1 到 4 字节,下标的 O(1) 承诺无法兑现,语言干脆禁止,逼你显式选择:.bytes() 按字节、.chars() 按字符、.len() 返回的是字节数不是字符数。处理中文时 "你好".len() 是 6——记住这个就不会再困惑。
示例
Vec 的增删读改与遍历:
fn main() {
let mut scores = vec![88, 92];
scores.push(79);
scores.push(95);
// get 安全访问
assert_eq!(scores.get(1), Some(&92));
assert_eq!(scores.get(99), None);
// 可变遍历:每人加 5 分
for s in &mut scores {
*s += 5;
}
assert_eq!(scores, vec![93, 97, 84, 100]);
let total: i32 = scores.iter().sum();
let avg = total as f64 / scores.len() as f64;
println!("平均分 {avg:.1}");
assert_eq!(total, 374);
}
String 的构建、拼接与 UTF-8 真相:
fn main() {
let mut s = String::from("你好");
s.push_str(",Rust");
s.push('!');
assert_eq!(s, "你好,Rust!");
// format! 拼接,两个原字符串都还能用
let name = String::from("小林");
let hello = format!("{s} 我是 {name}");
println!("{hello}");
assert!(hello.contains("小林"));
// len() 是字节数;字符数要用 chars().count()
assert_eq!("你好".len(), 6);
assert_eq!("你好".chars().count(), 2);
}
常见坑
- v[i] 越界 panic:下标来自外部输入时一律用 .get(i);确信界内才用下标,并把「确信」写成注释。
- 遍历时增删元素:for x in &v { v.push(...) } 借用冲突编译不过;常见解法是先 collect 出要加的,再 extend。
- 用 + 连一串字符串:s1 + &s2 + &s3 每步都移动所有权,又长又绕;format! 一次成型,原值全部保留。
- 把 len() 当字符数:对中文/emoji 文本,len() 是字节数;要「多少个字」用 .chars().count(),要按字符处理就用 .chars() 迭代。
小结
Vec:vec! 建、push 增、get 安全读、&/&mut/值三种遍历。String:UTF-8 的 Vec,push_str 追加、format! 拼接、禁止下标取字符、len() 是字节数。下一章:HashMap 与集合家族。