七、Rust 字符串

Rust 语言提供了两种字符串

  • 字符串字面量 &str。它是 Rust 核心内置的数据类型。
  • 字符串对象 String。它不是 Rust 核心的一部分,只是 Rust 标准库中的一个 公开 pub 结构体

7.1 字符串字面量 &str

字符串字面量 &str 就是在 编译时 就知道其值的字符串类型,是 Rust 语言核心的一部分。 字符串字面量 &str 是字符的集合,被硬编码赋值给一个变量。

  1. let name1 = "你好,零基础教程 简单编程";

字符串字面量的核心代码可以在模块 std::str 中找到,如果你有兴趣,可以阅读一二。

Rust 中的字符串字面量被称之为 字符串切片。因为它的底层实现是 切片

7.1.1 范例

下面的代码,我们定义了两个字符串字面量 company 和 location

  1. fn main() {
  2. let company:&str="零基础教程";
  3. let location:&str = "中国";
  4. println!("公司名 : {} 位于 :{}",company,location);
  5. }

字符串字面量模式是 静态 的。 这就意味着字符串字面量从创建时开始会一直保存到程序结束。

因为默认是 静态 的,我们也可以主动添加 static 关键字。只不过语法格式有点怪,所以日常使用还是忽略吧。

  1. fn main() {
  2. let company:&'static str = "零基础教程";
  3. let location:&'static str = "中国";
  4. println!("公司名 : {} 位于 :{}",company,location);
  5. }

编译运行以上 Rust 代码,输出结果如下

  1. 公司名 : 零基础教程 位于 :中国

7.2 字符串对象

字符串对象是 Rust 标准库提供的内建类型。

与字符串字面量不同的是:字符串对象并不是 Rust 核心内置的数据类型,它只是标准库中的一个 公开 pub 的结构体。

字符串对象在标准库中的定义语法如下

  1. pub struct String

字符串对象是是一个 长度可变的集合,它是 可变 的而且使用 UTF-8 作为底层数据编码格式。

字符串对象在 堆 heap 中分配,可以在运行时提供字符串值以及相应的操作方法。

7.2.1 创建字符串对象的语法

要创建一个字符串对象,有两种方法:

  1. 一种是创建一个新的空字符串,使用 String::new() 静态方法
  1. String::new()
  1. 另一种是根据指定的字符串字面量来创建字符串对象,使用 String::from() 方法
  1. String::from()

7.2.2 范例

下面,我们分别使用 String::new() 方法和 String::from() 方法创建字符串对象,并输出字符串对象的长度

  1. fn main(){
  2. let empty_string = String::new();
  3. println!("长度是 {}",empty_string.len());
  4. let content_string = String::from("零基础教程");
  5. println!("长度是 {}",content_string.len());
  6. }

编译运行以上 Rust 代码,输出结果如下

  1. 长度是 0
  2. 长度是 12

The above example creates two strings − an empty string object using the new method and a string object from string literal using the from method.

7.3 字符串对象常用的方法

方法 原型 说明
new() pub const fn new() -> String 创建一个新的字符串对象
to_string() fn to_string(&self) -> String 将字符串字面量转换为字符串对象
replace() pub fn replace<’a, P>(&’a self, from: P, to: &str) -> String 搜索指定模式并替换
as_str() pub fn as_str(&self) -> &str 将字符串对象转换为字符串字面量
push() pub fn push(&mut self, ch: char) 再字符串末尾追加字符
push_str() pub fn push_str(&mut self, string: &str) 再字符串末尾追加字符串
len() pub fn len(&self) -> usize 返回字符串的字节长度
trim() pub fn trim(&self) -> &str 去除字符串首尾的空白符
split_whitespace() pub fn split_whitespace(&self) -> SplitWhitespace 根据空白符分割字符串并返回分割后的迭代器
split() pub fn split<’a, P>(&’a self, pat: P) -> Split<’a, P> 根据指定模式分割字符串并返回分割后的迭代器。模式 P 可以是字符串字面量或字符或一个返回分割符的闭包
chars() pub fn chars(&self) -> Chars 返回字符串所有字符组成的迭代器

7.4 创建一个新的空字符串对象 new()

如果要创建一个新的空字符串对象,我们可以调用 new() 方法。

  1. fn main(){
  2. let mut z = String::new();
  3. z.push_str("零基础教程 简单编程");
  4. println!("{}",z);
  5. }

编译运行以上 Rust 代码,输出结果如下

  1. 零基础教程 简单编程

7.5 字符串字面量转换为字符串对象 to_string()

字符串字面量是没有任何操作方法的,它仅仅只保存了 字符串 本身。

其实是有的,就是 to_string()

如果要对字符串进行一些操作,就必须将字符串转换为字符串对象。而这个转换过程,可以通过调用 to_string() 方法

  1. fn main(){
  2. let name1 = "你好,零基础教程
  3. 简单编程".to_string();
  4. println!("{}",name1);
  5. }

编译运行以上 Rust 代码,输出结果如下

  1. 你好,零基础教程
  2. 简单编程

7.6 字符串替换 replace()

如果要一个字符串对象中的指定字符串子串替换成另一个字符串,可以调用 replace() 方法。

replace() 方法接受两个参数:

  • 第一个参数是要被替换的字符串子串或模式。
  • 第二个参数是新替换的字符串。

    注意: replace() 会搜索和替换所有要被替换的字符串子串或模式。

7.6.1 范例

下面的代码,我们搜索字符串中所有的 程 字,并替换成 www.badu.com

  1. fn main(){
  2. let name1 = "零基础教程 简单编
  3. 程".to_string(); //原字符串对象
  4. let name2 = name1.replace("程","www.badu.com"); // 查找并替换
  5. println!("{}",name2);
  6. }

编译运行以上 Rust 代码,输出结果如下

  1. 简单教www.badu.com 简单编
  2. www.badu.com

7.7 将字符串对象转换为字符串字面量 as_str()

字符串字面量就是字符串那些字符,比如

  1. let name1 = "零基础教程";

name1 是一个字符串字面量,它只包含 零基础教程 四个字本身。

字符串字面量只包含字符串本身,并没有提供相应的操作方法。

如果要返回一个字符串对象的 字符串 字面量,则可以调用 as_str() 方法

  1. fn main() {
  2. let example_string = String::from("零基础教程");
  3. print_literal(example_string.as_str());
  4. }
  5. fn print_literal(data:&str ){
  6. println!("显示的字符串字面量是: {}",data);
  7. }

编译运行以上 Rust 代码,输出结果如下

  1. 显示的字符串字面量是: 零基础教程

7.8 原字符串后追加字符 push()

如果要在一个字符串后面追加字符则首先需要将该字符串声明为 可变 的,也就是使用 mut 关键字。然后再调用 push() 方法。

push() 是在原字符上追加,而不是返回一个新的字符串

  1. fn main(){
  2. let mut company = "零基础教程".to_string();
  3. company.push('t');
  4. println!("{}",company);
  5. }

编译运行以上 Rust 代码,输出结果如下

  1. 零基础教程t

7.9 原字符串后追加字符串 push_str()

如果要在一个字符串后面追加字符串则首先需要将该字符串声明为 可变 的,也就是使用 mut 关键字。然后再调用 push_str() 方法。

push_str() 是在原字符上追加,而不是返回一个新的字符串

  1. fn main(){
  2. let mut company = "零基础教程".to_string();
  3. company.push_str(" 简单编程");
  4. println!("{}",company);
  5. }

编译运行以上 Rust 代码,输出结果如下

  1. 零基础教程 简单编程

7.10 获取字符串长度 len()

如果要返回字符串中的总字节数可以使用 len() 方法。

len() 方法会统计所有的字符,包括空白符。

空白符是指 制表符 \t、空格 、回车 \r、换行 \n 和回车换行 \r\n 等等。

  1. fn main() {
  2. let fullname = " 零基础教程 简单编程 www.badu.com";
  3. println!("length is {}",fullname.len());
  4. }

编译运行以上 Rust 代码,输出结果如下

  1. length is 38

7.11 去除字符串头尾的空白符 trim()

空白符是指 制表符 \t、空格 、回车 \r、换行 \n 和回车换行 \r\n 等等。

如果要去掉字符串头尾的空白符,可以使用 trim() 方法。

该方法并不会去掉不是头尾的空白符,而且该方法会返回一个新的字符串。

  1. fn main() {
  2. let fullname = " \t简单\t教程 \r\n简单
  3. 编程\r\n ";
  4. println!("Before trim ");
  5. println!("length is {}",fullname.len());
  6. println!();
  7. println!("After trim ");
  8. println!("length is {}",fullname.trim().len());
  9. println!("string is :{}",fullname.trim());
  10. }

编译运行以上 Rust 代码,输出结果如下

  1. Before trim
  2. length is 41
  3. After trim
  4. length is 32
  5. string is :简单 教程
  6. 简单
  7. 编程

7.12 使用空白符分割字符串 split_whitespace()

空白符是指 制表符 \t、空格 、回车 \r、换行 \n 和回车换行 \r\n 等等。

根据空白符分割字符串是最常用的操作之一,为此,Rust 语言为字符串提供了 split_whitespace() 用于根据空白符 分割一个字符串并返回一个迭代器。

我们可以使用这个迭代器来访问分割后的字符串。

  1. fn main(){
  2. let msg = "零基础教程 简单编程 www.badu.com
  3. https://www.badu.com".to_string();
  4. let mut i = 1;
  5. for token in msg.split_whitespace(){
  6. println!("token {} {}",i,token);
  7. i+=1;
  8. }
  9. }

编译运行以上 Rust 代码,输出结果如下

  1. token 1 零基础教程
  2. token 2 简单编程
  3. token 3 www.badu.com
  4. token 4 https://www.badu.com

根据指定模式分割字符串 split()

如果要将字符串根据某些指定的 字符串子串 分割,则可以使用 split() 方法。

split() 会根据传递的指定 模式 (字符串分割符) 来分割字符串,并返回分割后的字符串子串组成的切片上的迭代器。我们可以通过这个迭代器来迭代分割的字符串子串。

split() 方法最大的缺点是不可重入迭代,也就是迭代器一旦使用,则需要重新调用才可以再用。

但我们可以先在迭代器上调用 collect() 方法将迭代器转换为 向量 Vector ,这样就可以重复使用了。

  1. fn main() {
  2. let fullname = "李白,诗仙,唐朝";
  3. for token in fullname.split(","){
  4. println!("token is {}",token);
  5. }
  6. // 存储在一个向量中
  7. println!("\n");
  8. let tokens:Vec<&str>= fullname.split(",").collect();
  9. println!("姓名 is {}",tokens[0]);
  10. println!("称号 {}",tokens[1]);
  11. println!("朝代 {}",tokens[2]);
  12. }

编译运行以上 Rust 代码,输出结果如下

  1. token is 李白
  2. token is 诗仙
  3. token is 唐朝
  4. 姓名 is 李白
  5. 称号 诗仙
  6. 朝代 唐朝

7.13 将字符串打散为字符数组 chars()

如果要将一个字符串打散为所有字符组成的数组,可以使用 chars() 方法。

从某些方面说,如果我们要迭代字符串中的每一个字符,则必须首先将它打散为字符数组,然后才能遍历。

  1. fn main(){
  2. let n1 = "零基础教程 www.badu.com".to_string();
  3. for n in n1.chars(){
  4. println!("{}",n);
  5. }
  6. }

编译运行以上 Rust 代码,输出结果如下

  1. w
  2. w
  3. w
  4. .
  5. t
  6. w
  7. l
  8. e
  9. .
  10. c
  11. n

7.14 字符串连接符 +

将一个字符串追加到另一个字符串的末尾,创建一个新的字符串,我们将这种操作称之为 连接,有时候也称之为 拼接差值

连接 的结果是创建一个新的字符串对象。

Rust 语言使用 加号 + 来完成这种 连接,我们称之为 字符串连接符

7.14.1 字符串连接符 + 的内部实现

字符串连接符 + 的内部实现,其实是重写了 add() 方法。该方法接受两个参数,第一个参数是当前的字符串对象 self ,也就是 + 左边的字符串,第二个参数是一个引用,它指向了 + 右边的字符串。

具体的方法原型如下

  1. //字符串拼接符的实现
  2. add(self,&str)->String {
  3. // 返回一个新的字符串对象
  4. }

7.14.2 范例

下面的代码,我们使用 字符串拼接符 + 将连个字符串变量拼接成一个新的字符串

  1. fn main(){
  2. let n1 = "零基础教程".to_string();
  3. let n2 = "简单编程".to_string();
  4. let n3 = n1 + &n2; // 需要传递 n2 的引用
  5. println!("{}",n3);
  6. }

编译运行以上 Rust 代码,输出结果如下

  1. 零基础教程 简单编程

7.15 类型转换 to_string()

如果需要将其它类型转换为字符串类型,可以直接调用 to_string() 方法。

例如可以调用一个数字类型的变量的 to_string() 方法将当前变量转换为字符串类型。

  1. fn main(){
  2. let number = 2020;
  3. let number_as_string = number.to_string();
  4. // 转换数字为字符串类型
  5. println!("{}",number_as_string);
  6. println!("{}",number_as_string=="2020");
  7. }

编译运行以上 Rust 代码,输出结果如下

  1. 2020
  2. true

7.16 格式化宏 format!

如果要把不同的变量或对象拼接成一个字符串,我们可以使用 格式化宏 ( format! )

格式化宏 format! 的使用方法如下

  1. fn main(){
  2. let n1 = "零基础教程".to_string();
  3. let n2 = "简单编程".to_string();
  4. let n3 = format!("{} {}",n1,n2);
  5. println!("{}",n3);
  6. }

编译运行以上 Rust 代码,输出结果如下

  1. 零基础教程 简单编程