Rust 字符串
处理文本,是 Rust 最早让你觉得“和别的语言不一样”的地方之一,主要是因为它其实有两种字符串类型。只要弄明白为什么,就不会再糊涂了。
&str 与 String
Section titled “&str 与 String”&str(字符串 slice):已经存在于某处的文本,通常就是你直接写在代码里的那种。大小固定,不能增长。String:一段有所有权、可以增长的文本。你可以往里面追加内容,它存放在堆上。
fn main() { let literal: &str = "hello"; // 一个字符串 slice let owned: String = String::from("hello"); // 一个有所有权的 String
println!("{literal} / {owned}");}一个简单的经验法则:如果只是打印固定的文本,"像这样" 写一个 &str 就够了。如果需要在运行时构建、增长或修改文本,就用 String。
让 String 变长
Section titled “让 String 变长”fn main() { let mut greeting = String::from("Hello"); greeting.push_str(", World"); // 追加一个 &str greeting.push('!'); // 追加单个 char
println!("{greeting}");}输出:
Hello, World!可以用 + 把字符串连起来,也可以用 format!(通常更清晰):
fn main() { let first = String::from("Hello, "); let second = String::from("World!");
let combined = first + &second; // 注意 second 前面的 & println!("{combined}");
// format! 往往更好读: let name = "Ferris"; let greeting = format!("Hello, {name}!"); println!("{greeting}");}常用字符串方法
Section titled “常用字符串方法”下面这几个你会经常用到:
fn main() { let text = " Hello, Rust! ";
println!("{}", text.trim()); // "Hello, Rust!"(去掉了两边的空格) println!("{}", text.to_uppercase()); // " HELLO, RUST! " println!("{}", text.to_lowercase()); // " hello, rust! " println!("{}", text.contains("Rust")); // true println!("{}", text.trim().len()); // 12(按字节计算的长度) println!("{}", text.trim().replace("Rust", "World")); // "Hello, World!"}这里的文本特意保留了英文:.len() 数的是字节,一个汉字在 UTF-8 里占 3 个字节,换成中文结果就不是 12 了。大小写转换也只对字母有意义。
要一个字符一个字符地处理,用 .chars():
fn main() { for c in "abc".chars() { println!("{c}"); }}1. 清理杂乱的输入
Section titled “1. 清理杂乱的输入”有人在表单里输入了 " rUsT is FUN "。把它变成 rust is great:去掉多余的空格,全部转成小写,再把 fun 换成 great。然后打印结果和它的长度。提示:字符串方法可以一个接一个地链式调用:text.trim().to_lowercase()...。
查看答案
fn main() { let input = " rUsT is FUN ";
// 先 trim,再转小写,最后替换 "fun"(此时已经是小写) let clean = input.trim().to_lowercase().replace("fun", "great");
println!("{clean}"); println!("{} 个字节", clean.len());}输出:
rust is great13 个字节顺序很重要:如果在 .to_lowercase() 之前调用 .replace("fun", "great"),什么都不会被替换,因为那时文本里写的还是 FUN。
2. 拼出一个邮箱地址
Section titled “2. 拼出一个邮箱地址”已知 first = "Ada"、last = "Lovelace",构建出 String 类型的 [email protected] 并打印出来。然后打印它是否包含 @。提示:format! 的 {} 占位符可以接收 first.to_lowercase() 这样的表达式作为参数。
查看答案
fn main() { let first = "Ada"; let last = "Lovelace";
let email = format!("{}.{}@example.com", first.to_lowercase(), last.to_lowercase());
println!("{email}"); println!("看起来有效:{}", email.contains('@'));}输出:
看起来有效:true&str是借用来的、固定的文本;String拥有所有权,可以增长。- 用
.push_str()(追加文本)或.push()(追加单个字符)让String变长。 - 拼接字符串时优先用
format!而不是+:更清晰,也不会移动任何值。 - 常用方法:
.trim()、.to_uppercase()、.contains()、.replace()、.chars()。
小测验
1. 哪种字符串类型拥有所有权,并且能在运行时增长?
2. 拼接两三段以上的字符串时,这一课为什么更推荐 format! 而不是 +?
3. 为什么不能像 text[0] 这样索引 Rust 字符串?
4. 要往 String 里追加单个字符(比如 greeting.push('!')),用哪个方法?
得分: 0 / 4
- 使用字符串储存 UTF-8 编码的文本 —《Rust 程序设计语言》:官方教程讲
String的一章,包括为什么不能按位置索引。 - Slice 类型 —《Rust 程序设计语言》:学完借用之后,再来看
&str到底是什么。 - 字符串 — 通过例子学 Rust:
String和&str的可运行示例,还有转义字符和原始字符串。 String— 标准库文档(英文):有所有权的String的全部方法,每个都配有小例子。str— 标准库文档(英文):trim、contains、replace、split等适用于任何文本的方法。