字符串
Rust 中最常用的两种字符串类型是 String
和 &str
。
String
存储为字节向量(Vec<u8>
),但保证始终是有效的 UTF-8 序列。String
在堆上分配,可增长,且不以 null 结尾。
&str
是一个切片(&[u8]
),它始终指向一个有效的 UTF-8 序列,可以用来查看 String
,就像 &[T]
是 Vec<T>
的一个视图一样。
fn main() { // (所有的类型注解都不是必须的) // 一个指向只读内存中分配的字符串的引用 let pangram: &'static str = "敏捷的棕色狐狸跳过懒惰的狗"; println!("全字母句:{}", pangram); // 反向遍历单词,不会分配新的字符串 println!("单词逆序"); for word in pangram.split_whitespace().rev() { println!("> {}", word); } // 将字符复制到向量中,排序并去重 let mut chars: Vec<char> = pangram.chars().collect(); chars.sort(); chars.dedup(); // 创建一个空的、可增长的 `String` let mut string = String::new(); for c in chars { // 在字符串末尾插入一个字符 string.push(c); // 在字符串末尾追加另一个字符串 string.push_str(", "); } // 修剪后的字符串是原始字符串的一个切片,因此不会进行新的内存分配 let chars_to_trim: &[char] = &[' ', ',']; let trimmed_str: &str = string.trim_matches(chars_to_trim); println!("使用的字符:{}", trimmed_str); // 在堆上分配一个字符串 let alice = String::from("我喜欢狗"); // 分配新的内存并在其中存储修改后的字符串 let bob: String = alice.replace("狗", "猫"); println!("爱丽丝说:{}", alice); println!("鲍勃说:{}", bob); }
更多 str
和 String
的方法可以在 std::str 和 std::string 模块中找到
字面值和转义字符
有多种方式可以编写包含特殊字符的字符串字面值。所有方式都会产生类似的 &str
,因此最好使用最方便编写的形式。同样,也有多种方式可以编写字节字符串字面值,它们都会产生 &[u8; N]
类型。
通常,特殊字符用反斜杠(\
)进行转义。这样你可以在字符串中添加任何字符,包括不可打印的字符和你不知道如何输入的字符。如果你想要一个字面的反斜杠,用另一个反斜杠转义它:\\
出现在字面值内的字符串或字符字面值分隔符必须被转义:"\""
和 '\''
。
fn main() { // 你可以使用转义来通过十六进制值写入字节... let byte_escape = "我正在写 \x52\x75\x73\x74!"; println!("你在做什么\x3F(\\x3F 表示 ?){}", byte_escape); // ...或 Unicode 码点。 let unicode_codepoint = "\u{211D}"; let character_name = "\"双线大写 R\""; println!("Unicode 字符 {} (U+211D) 被称为 {}", unicode_codepoint, character_name ); let long_string = "字符串字面值 可以跨越多行。 这里的换行和缩进 ->\ <- 也可以被转义!"; println!("{}", long_string); }
有时需要转义的字符太多,或者直接按原样写出字符串会更方便。这时就可以使用原始字符串字面值。
fn main() { let raw_str = r"转义在这里不起作用:\x3F \u{211D}"; println!("{}", raw_str); // 如果你需要在原始字符串中使用引号,可以添加一对 # let quotes = r#"然后我说:"无处可逃!""#; println!("{}", quotes); // 如果你需要在字符串中使用 "#,只需在分隔符中使用更多的 #。 // 你最多可以使用 255 个 #。 let longer_delimiter = r###"一个包含 "# 的字符串。甚至还有 "##!"###; println!("{}", longer_delimiter); }
想要一个非 UTF-8 的字符串吗?(请记住,str
和 String
必须是有效的 UTF-8)。或者你想要一个主要是文本的字节数组?字节字符串来帮忙!
use std::str; fn main() { // 注意,这实际上不是一个 `&str` let bytestring: &[u8; 21] = b"这是一个字节字符串"; // 字节数组没有 `Display` trait,所以打印它们有一些限制 println!("一个字节字符串:{:?}", bytestring); // 字节字符串可以包含字节转义... let escaped = b"\x52\x75\x73\x74 作为字节"; // ...但不允许 Unicode 转义 // let escaped = b"\u{211D} 是不允许的"; println!("一些转义的字节:{:?}", escaped); // 原始字节字符串的工作方式与原始字符串相同 let raw_bytestring = br"\u{211D} 在这里不会被转义"; println!("{:?}", raw_bytestring); // 将字节数组转换为 `str` 可能会失败 if let Ok(my_str) = str::from_utf8(raw_bytestring) { println!("作为文本的相同内容:'{}'", my_str); } let _quotes = br#"你也可以使用"更花哨的"格式,\ 就像普通的原始字符串一样"#; // 字节字符串不必是 UTF-8 编码 let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; // SHIFT-JIS 编码的 "ようこそ" // 但它们并不总是能被转换为 `str` match str::from_utf8(shift_jis) { Ok(my_str) => println!("转换成功:'{}'", my_str), Err(e) => println!("转换失败:{:?}", e), }; }
对于字符编码之间的转换,请查看 encoding crate。
关于编写字符串字面值和转义字符的更详细说明,请参阅 Rust 参考手册的「标记」章节。