字符串与切片

15 阅读3分钟

字符串

  • Rust 中的字符串类型 String 是可变的、可增长的 UTF-8 编码字符串。
  • 字符串字面量(如 "Hello, world!")是不可变的,其类型是 &str。

字符串类型错误示例

fn main() {
  let my_name = "Pascal";
  greet(my_name); // 错误:期望 String 类型,但提供了 &str 类型
}

fn greet(name: String) {
  println!("Hello, {}!", name);
}

切片(Slice)

  • 切片是对集合中连续元素序列的引用,不拥有数据。
  • 字符串切片的语法:&s[start..end]。

字符串切片示例

fn main() {
  let s = String::from("hello world");
  let hello = &s[0..5];
  let world = &s[6..11];
}

字符串字面量是切片

  • 字符串字面量(如 "中国人")的类型是 &str。

String 与 &str 的转换

  • String::from("...") 和 "...".to_string() 可从字符串字面量创建 String 类型。
  • 通过取引用 &s 或 s[..] 将 String 类型转为 &str 类型。

String 与 &str 转换示例

fn main() {
  let s = String::from("hello, world!");
  say_hello(&s);
  say_hello(&s[..]);
  say_hello(s.as_str());
}

fn say_hello(s: &str) {
  println!("{}", s);
}

字符串索引

  • Rust 中不能直接通过索引访问字符串的字符,因为字符串是 UTF-8 编码,索引可能落在字符的中间。

字符串索引错误示例

fn main() {
  let s1 = String::from("hello");
  let h = s1[0]; // 错误:String 不能被索引
}

操作字符串

  • String 类型提供了多种方法来修改字符串,如 push, push_str, insert, insert_str, replace, replacen, replace_range, pop, remove, truncate, clear。

字符串追加示例

fn main() {
  let mut s = String::from("Hello ");
  s.push_str("rust");
  println!("追加字符串 push_str() -> {}", s);

  s.push('!');
  println!("追加字符 push() -> {}", s);
}

字符串插入示例

fn main() {
  let mut s = String::from("Hello rust!");
  s.insert(5, ',');
  println!("插入字符 insert() -> {}", s);

  s.insert_str(6, " I like");
  println!("插入字符串 insert_str() -> {}", s);
}

字符串删除示例

fn main() {
  let mut s = String::from("Hello, world!");
  s.pop(); // 删除并返回字符串的最后一个字符
  println!("删除最后一个字符 pop() -> {}", s);

  s.remove(5); // 删除指定位置的字符
  println!("删除指定位置字符 remove() -> {}", s);

  s.truncate(5); // 删除从指定位置到结尾的字符
  println!("截断字符串 truncate() -> {}", s);

  s.clear(); // 清空字符串
  println!("清空字符串 clear() -> {}", s);
}

字符串连接

  • 使用 + 或 format! 宏可以连接字符串。

字符串连接示例

fn main() {
  let s1 = String::from("hello ");
  let s2 = "rust";
  let result = s1 + s2; // 返回一个新的 String

  let s3 = result + "!";
  println!("连接字符串 + -> {}", s3);
}

字符串转义

  • 使用 \ 进行转义,可以输出特殊字符和 Unicode 字符。

字符串转义示例

fn main() {
  let byte_escape = "I'm writing \x52\x75\x73\x74!";
  println!("What are you doing\x3F (\x3F means ?) {}", byte_escape);

  let unicode_codepoint = "\u{211D}";
  let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";
  println!("Unicode character {} (U+211D) is called {}", unicode_codepoint, character_name);
}

操作 UTF-8 字符串

  • 使用 chars 方法遍历 Unicode 字符。
  • 使用 bytes 方法遍历字符串的底层字节。

字符遍历示例

fn main() {
  for c in "中国人".chars() {
    println!("{}", c);
  }
}

字节遍历示例

fn main() {
  for b in "中国人".bytes() {
    println!("{}", b);
  }
}

字符串深度剖析

  • 字符串字面值在编译时硬编码进可执行文件,因此是不可变的。
  • String 类型在堆上分配内存,支持可变和可增长的文本片段。

总结

  • Rust 中的字符串处理考虑了 UTF-8 编码的特性,避免了潜在的运行时错误。
  • 字符串字面值是不可变的 &str 类型,而 String 是可变的、可增长的。
  • 通过各种方法,可以灵活地操作和连接字符串。