Rust 笔记:Rust 语言中的字符串

简介: Rust 笔记:Rust 语言中的字符串

Rust 笔记Rust 语言中的字符串


1. 概述

本文介绍 Rust 语言中的 字符字符串。在 Rust 语言中,不仅 字符 和 字符串 是不同的类型,并且还存在着 strString 两种字符串。

Rust 中的字符类型是 char,它表示 Unicode 标量值,占用 4 个字节,而字符串类型是 str 和 String。str 类型是一种不可变的字符串类型,通常使用 &str 来表示,而 String 类型是一种可变的字符串类型,通常使用 String 来表示。

2. Rust 的 字符 类型

2.1 Rust 中的 字符(char)类型

2.1.1 char 类型的概念

Rust 的 char 类型是该语言最原始的字母类型。该类型 在 Rust 表示 Unicode 标量值,它占用 4 个字节,可以使用 单引号 来表示一个 char 类型的值,例如:

let a = 'a'; // 常规的 ASCII 字符
let b = '😎'; // Unicode 表情符号
let c = '\u{1F600}'; // 同样是 Unicode 表情符号,使用 Unicode 标量值表示

2.1.2 在 char 类型 里 使用 转义字符

现代高级语言中,如 CJavaScriptPython,都使用 转义符 来表示一些特殊的字符, Rust 也不例外,其中的转义字符使用 反斜杠\)来表示,例如:

let a = '\n'; // 换行符
let b = '\t'; // 制表符
let c = '\''; // 单引号

由于反斜杠被用作 转义符,这意味着只有一个反斜杠表示的不是反斜杠自身,因此如果你要使用反斜杠,则加一个反斜杠对其进行转义,也就是:

let d = '\\'; // 反斜杠

在这一小节的例子中,我们使用的都是 单引号,可知这里的转义符针对的是 字符 类型。实际上 Rust 中,也可以将其用于 字符串 类型(在后面介绍)。

2.1.3 char 类型 与其它类型的转换

Rust 语言中提供了 as 关键字,与 TypeScript 中的 as 关键字仅仅是用于 类型断言 不同,在 Rust 语言中,as 的直接将 一个类型 转换为 另一个类型,而不仅仅是视作另一个类型。

因此我们可以通过 as 将 char 类型转换为 u8 类型,或者将 u8 类型转换为 char 类型:

let a = 'a';
let b = a as u8; // char 类型转换为 u8 类型
let c = b as char; // u8 类型转换为 char 类型

或者

let d = '😀';
let e = d as u32; // char 类型转换为 u32 类型
let f = e as char; // u32 类型转换为 char 类型

2.1.4 在字符(char)实例上提供的一些方法

我们可以调用 char 原生支持的一些方法,实现某些功能。

char 类型上用于判断的相关方法
方法 描述
is_ascii 判断是否是 ASCII 字符
is_alphabetic 判断是否是字母
is_digit 判断是否是十进制数字
is_lowercase 判断是否是小写字母
is_uppercase 判断是否是大写字母

例如:

let a = 'A';
let m = a.is_ascii();      // 判断是否是 ASCII 字符
let n = a.is_alphabetic(); // 判断是否是字母
let o = a.is_digit(10);    // 判断是否是十进制数字
let p = a.is_lowercase();  // 判断是否是小写字母
let q = a.is_uppercase();  // 判断是否是大写字母
char 类型上用于转换的相关方法
方法 描述
to_ascii_lowercase 转换为小写字母
to_ascii_uppercase 转换为大写字母

例如:

let c = 'C';
let l = c.to_ascii_lowercase(); // 转换为对应的小写字母 => c
let s = 's'
let u = s.to_ascii_uppercase(); // 转换为对应的大写字母 => S

2.2 从字符到字符串

2.2.1 什么是字符串

顾名思义,将一串字符穿在一起就形成了 字符串。字符串是非常重要的数据类型,因为它们可以用于表示文本数据,例如文件内容、用户输入、网络数据等等。现实生活中的文本、句子都需要使用字符串而不是单个字符进行表示。

字符串还可以用于格式化输出,例如将数字转换为字符串,或将字符串转换为数字。

在Rust语言中,str类型的 字符串是一种不可变的数据类型,用于表示文本数据。字符串是 由字符组成的序列。str类型是一种不可变的字符串类型,通常使用&str来表示。String类型是一种可变的字符串类型,通常使用String来表示。

2.2.2 字符 和 字符串的异同

Rust 语言中,字符和字符串相比:

  1. 字符类型(char)是单个字符,而 字符串strString)是多个字符 组成的序列;
  2. 字符类型(char)是不可变的,String 类型的字符串类型可以是可变的;
  3. 字符类型通常使用 单引号表示,字符串类型通常使用 双引号 或者S tring::from方法 创建;
  4. 字符字符串 类型 都可以 使用一些特殊的 转义字符,如换行符、制表符等,字符串类型也支持这些转义字符。
  5. 字符 类型 支持的一些方法,如 is_ascii、is_alphabetic、is_digit,同样在字符串中也支持。

3. 不可变字符串类型 str

3.1 str 类型概述

Rust 语言中,str 类型 是一种不可变的字符串类型,通常使用 &str 来表示。创建 str 类型 的方法有很多,比如最简单的就是使用 双引号语法,该方法可以非常方便地创建 str 字面量:

let s1 = "hello world!"; // 直接使用字符串字面量创建
let s2: &str = "hello";  // 使用类型注解创建

str 也可以是通过可变字符串 String转换来的:

let s3 = String::from("world").as_str(); // 使用 String 类型的 as_str 方法创建

或者使用可变字符串 String 类型的引用创建不可变字符串 str 类型地字面量:

let s4 = &String::from("world"); // 使用 String 类型的引用创建

3.2 不可变字符串str的特点

3.2.1 不可变字符串str的优点

不可变字符串具有以下有点

  1. 安全性高:不可变字符串不会被意外修改,避免了一些潜在的错误。
  2. 性能高:不可变字符串的内存布局更加紧凑,访问速度更快。

3.2.2 不可变字符串str的不足

不可变字符串也有一些不足,比如:

  1. 不可变字符串无法修改,需要重新创建一个新的字符串来实现修改操作,会占用更多的内存空间。
  2. 不可变字符串无法直接拼接,需要使用 format! 宏 或者 String::from 方法来实现。

3.2.3 如何选用 字符串str

一般以下,可以参考以下建议选择字符串:

  1. 字符串不需要修改时,选用不可变字符串 str ,这样更加 安全 和 高效;
  2. 反之,字符串需要修改时,选用可变字符串 String

3.3 如何判断一个值的类型为str

判断一个值是否是 str 类型可以使用类型判断语法:

fn is_str(s: &dyn std::any::Any) -> bool {
    s.is::<&str>()
}

例如:

let s1 = "hello";
let s2 = String::from("world");
let s3 = 123;
let s4 = vec![1, 2, 3];
println!("{}", is_str(&s1));   // true
println!("{}", is_str(&s2));   // false
println!("{}", is_str(&s3));   // false
println!("{}", is_str(&s4));   // false

4. 可变字符串类型 String

4.1 快速入门可变字符串 String

4.1.1 什么是可变字符串

可变字符串的 可变 是相对于不可变字符串而言的,我们上一节使用字面量语法创建的字符串已经创建就不可以修改了,因而称之为不可变字符串。

换而言之,可变字符串的可变指的是字符串的内容可以被修改。例如,使用 push_str 方法可以在字符串末尾添加字符串字面量:

let mut s1 = String::from("hello");
s1.push_str(", world!");   // 在字符串末尾添加字符串字面量
println!("{}", s1);        // 输出:hello, world!

可以看到,通过这样的方法,使得字符串的内容发生了变化。类似的方法还有很多,请参考 4.2 String 方法解析 部分。

4.1.2 String 类型 与 str 类型的区别

  1. str 类型是不可变的,而 String 类型是可变的。
  2. str 类型通常用于函数参数和返回值,而 String 类型通常用于变量和常量。
  3. str 类型通常使用 字符串字面量 创建,而 String 类型通常使用 String::from 方法 创建。关于创建 String 的方法,请参考下一小节

4.1.3 如何创建String

通过使用 String::new 方法创建

使用 String::new 方法可以创建一个空的 String 类型的实例,例如:

let s1 = String::new(); // 创建一个空的 String 类型
通过使用 String::from 方法创建

String::from 方法可以直接使用字符串字面量创建 String,例如:

let s2 = String::from("hello");

实际上,你也可以理解为将一个 str 转换为对应的 String

通过 str 类型的 to_string 方法创建

不可变字符串 str 上提供了一个 to_string 方法,返回对应的 String 字符串。例如:

let s3 = "world".to_string();
通过 format! 宏创建

你还可以使用 format! 宏 来创建 String 字符串。例如:

let s4 = format!("{} {}", "hello", "world");

关于 format! 宏 ,请参考 4.3 format! 宏 与 模板字符串的使用

4.2 String 用法解析

4.2.1 字符串拼接

使用 + 操作符可以用于拼接两个字符串例如:

let s1 = String::from("Hello ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 使用 + 运算符连接两个字符串
println!("{}", s3); // 输出:Hello world!

4.2.2 字符串的切片

所谓 切片,指的是通过指定一对起止字符在字符串中的 位序,从而获得一个子字符串的方法。和诸多编程语言一样(如Python),可以使用 [] 语法对字符串进行切片。如:

let s1 = String::from("hello");
let s2 = &s1[0..2];     // 使用切片获取字符串的一部分
println!("{}", s2);     // 输出:he

4.2.3 clone 方法拷贝字符串

Stringclone 方法从原 String 对象实例上拷贝得到一个副本,例如:

let s1 = String::from("hello");
let s2 = s1.clone(); // 使用 clone 方法复制一个字符串
println!("{}", s2); // 输出:hello

4.2.4 trim 方法去除两端空白字符

在字符串处理的时候经常需要处理掉字符串两端的空白字符,使用 Stringtrim 方法即可轻松实现,例如:

例如:

let s1 = String::from("hello");
let s2 = s1.trim();
println!("{}", s9); // 输出:hello

4.2.5 chars 方法及其应用

String 的 chars 方法

Stringchars 方法用于获取字符串的字符迭代器。

例如:

let s1 = String::from("hello");
let s2 = s1.chars(); // 获取字符串的字符迭代器
for c in s23 {
    println!("{}", c); // 逐个输出字符串的字符
}
通过 chars 方法获取 字符串首字符

例如:

let s1 = String::from("hello");
let s2 = s1.chars().nth(0).unwrap(); // 获取字符串的第一个字符
println!("{}", s2); // 输出:h
通过 chars 方法获取 字符串尾字符

例如:

let s1 = String::from("hello");
let s2 = s1.chars().last().unwrap(); // 获取字符串的最后一个字符
println!("{}", s2); // 输出:o
通过 chars 方法获取 字符串的字符数

例如:

let s1 = String::from("hello");
let s2 = s1.chars().count(); // 获取字符串的字符数
println!("{}", s2); // 输出:5
通过 chars 方法 反转字符串

例如:

let s1 = String::from("hello");
let s2 = s1.chars().rev().collect::<String>(); // 将字符串反转
println!("{}", s2); // 输出:olleh

4.2.6 to_uppercase 方法将字符串统一为大写字母形式

例如:

let s1 = String::from("hEllo");
let s2 = s1.to_uppercase(); // 将字符串转换为大写字母形式
println!("{}", s2); // 输出:HELLO

4.2.7 to_lowercase 方法将字符串统一为大写字母形式

例如:

let s1 = String::from("heLLo");
let s2 = s1.to_lowercase(); // 将字符串转换为小写字母形式
println!("{}", s2); // 输出:hello

4.2.8 len 方法获取字符串的长度

例如:

let length = String::from("world").len(); // 5

4.2.9 contains 方法判断字符串是否包含指定的子串

例如:

let isContains = String::from("Hello").contains("llo"); // true

4.2.10 push 方法在字符串末尾添加单个字符

例如:

let mut s = String::from("Hello");
s.push('!');
println!("{}", s); // 输出:Hello!

4.2.11 push_str 方法在字符串末尾添加字符串字面量

例如:

let mut s = String::from("hello");
s.push_str(", world!"); 
println!("{}", s); // 输出:hello, world!

4.2.12 pop 方法移除字符串末尾的字符

例如:

let mut s = String::from("hello!");
s.pop(); // 移除字符串末尾的字符
println!("{}", s); // 输出:hello

4.2.13 remove 方法移除字符串指定为序处的字符

例如:

let mut s = String::from("hello");
s.remove(2);
println!("{}", s); // 输出:helo

4.2.14 insert 方法在字符串指定位置插入内容

内容可以是 charstr

例如在字符串指定位置插入单个字符:

let mut s = String::from("helo");
s.insert(2, 'l'); // 
println!("{}", s); // 输出:hello

又如在字符串指定位置插入字符串字面量:

let mut s = String::from("heo");
s.insert(1, "ll"); 
println!("{}", s); // 输出:hello

4.2.15 replace_range 方法替换字符串指定范围内的内容

例如:

let mut s = String::from("hello");
s.replace_range(1..3, "a"); 
println!("{}", s); // 输出:hallo

4.2.16 truncate 方法截断字符串

truncate 方法可以用于截断字符串,只保留指定长度的内容。例如:

let mut s = String::from("hello");
s.truncate(3);
println!("{}", s); // 输出:hel

4.2.17 clear 方法清空字符串的内容

字符串是字符的容器,清空字符串就得到一个没有任何字符的字符串,也称空字符串。

例如:

let mut s = String::from("hello");
s.clear();
println!("{}", s); // 输出:

4.2.18 字符串中使用转义符、原始字符串

字符串中使用转义符

在介绍 Rust 字符的时候我们介绍过转义符,Rust 中的字符串类型也支持转义字符,例如:

let s1 = "hello\nworld"; // 换行符
let s2 = "hello\tworld"; // 制表符
let s3 = "hello\'world"; // 单引号
let s4 = "hello\\world"; // 反斜杠

也可以使用转义符表示 Unicode 标量值,例如:

let s1 = "\u{1F600}"; // Unicode 表情符号
let s2 = "\u{1F600}\u{1F601}\u{1F602}"; // 多个 Unicode 表情符号
原始字符串表示

在 Rust 中,字符串前的 r# 表示使用原始字符串表示法,不会转义字符。例如:

let s1 = r#"hello\nworld"#;
println!("{}", s1); // 输出:hello\nworld

原始字符串表示法还支持使用多个 # 号,例如:

let s2 = r##"hello "world""##;
println!("{}", s2); // 输出:hello "world"

使用原始字符串表示法可以避免一些转义字符带来的麻烦,比如在正则表达式中使用反斜杠。例如:

let s3 = r"\d+";
println!("{}", s3); // 输出:\d+

4.3 format! 宏 与 模板字符串的使用

Rust 中的 format! 宏 用于格式化字符串,比如:

let s1 = format!("{} {}", "hello", "world"); // 使用位置占位符
let s2 = format!("{name} {age}", name = "Alice", age = 18); // 使用命名占位符
let s3 = format!("{:?}", vec![1, 2, 3]); // 将 Vec 转换为字符串

format! 宏 还支持一些高级特性,如:

let s4 = format!("{:x}", 255);        // 将数字转换为十六进制字符串
let s5 = format!("{:b}", 255);        // 将数字转换为二进制字符串
let s6 = format!("{:o}", 255);        // 将数字转换为八进制字符串
let s7 = format!("{:.2}", 3.1415926); // 将浮点数保留两位小数
let s8 = format!("{:+}", 123);        // 将数字添加正负号
let s9 = format!("{:*>10}", "hello"); // 将字符串右对齐并填充 *
let s10 = format!("{:^10}", "hello"); // 将字符串居中对齐
目录
相关文章
|
1月前
|
Rust 安全 Java
探索Rust语言的并发编程模型
探索Rust语言的并发编程模型
|
1月前
|
Rust 安全 区块链
探索Rust语言:系统编程的新选择
【10月更文挑战第27天】Rust语言以其安全性、性能和并发性在系统编程领域受到广泛关注。本文介绍了Rust的核心特性,如内存安全、高性能和强大的并发模型,以及开发技巧和实用工具,展示了Rust如何改变系统编程的面貌,并展望了其在WebAssembly、区块链和嵌入式系统等领域的未来应用。
|
1月前
|
Rust 安全 Java
编程语言新宠:Rust语言的特性、优势与实战入门
【10月更文挑战第27天】Rust语言以其独特的特性和优势在编程领域迅速崛起。本文介绍Rust的核心特性,如所有权系统和强大的并发处理能力,以及其性能和安全性优势。通过实战示例,如“Hello, World!”和线程编程,帮助读者快速入门Rust。
72 1
|
1月前
|
Rust 安全 编译器
编程语言新宠:Rust语言的特性、优势与实战入门
【10月更文挑战第26天】Rust语言诞生于2006年,由Mozilla公司的Graydon Hoare发起。作为一门系统编程语言,Rust专注于安全和高性能。通过所有权系统和生命周期管理,Rust在编译期就能消除内存泄漏等问题,适用于操作系统、嵌入式系统等高可靠性场景。
89 2
|
1月前
|
Rust 安全
深入理解Rust语言的所有权系统
深入理解Rust语言的所有权系统
36 0
|
1月前
|
Rust 安全 前端开发
探索Rust语言的异步编程模型
探索Rust语言的异步编程模型
|
1月前
|
Rust 安全 云计算
Rust语言入门:安全性与并发性的完美结合
【10月更文挑战第25天】Rust 是一种系统级编程语言,以其独特的安全性和并发性保障而著称。它提供了与 C 和 C++ 相当的性能,同时确保内存安全,避免了常见的安全问题。Rust 的所有权系统通过编译时检查保证内存安全,其零成本抽象设计使得抽象不会带来额外的性能开销。Rust 还提供了强大的并发编程工具,如线程、消息传递和原子操作,确保了数据竞争的编译时检测。这些特性使 Rust 成为编写高效、安全并发代码的理想选择。
29 0
|
4月前
|
Rust 安全 Go
揭秘Rust语言:为何它能让你在编程江湖中,既安全驰骋又高效超车,颠覆你的编程世界观!
【8月更文挑战第31天】Rust 是一门新兴的系统级编程语言,以其卓越的安全性、高性能和强大的并发能力著称。它通过独特的所有权和借用检查机制解决了内存安全问题,使开发者既能享受 C/C++ 的性能,又能避免常见的内存错误。Rust 支持零成本抽象,确保高级抽象不牺牲性能,同时提供模块化和并发编程支持,适用于系统应用、嵌入式设备及网络服务等多种场景。从简单的 “Hello World” 程序到复杂的系统开发,Rust 正逐渐成为现代软件开发的热门选择。
74 1
|
2月前
|
Rust 安全 网络安全
在 Rust 语言中,寻找企业上网行为管理软件的突破
在数字化企业环境中,上网行为管理软件对于保障网络安全和提升工作效率至关重要。Rust 语言凭借其安全性、高性能和并发性,为开发此类软件提供了新机遇。本文通过几个 Rust 代码示例,展示了如何实现网址检查、访问频率统计及访问控制等功能,旨在探索 Rust 在企业上网行为管理中的应用潜力。
42 0
|
4月前
|
Rust 安全 编译器
初探 Rust 语言与环境搭建
Rust 是一门始于2006年的系统编程语言,由Mozilla研究员Graydon Hoare发起,旨在确保内存安全而不牺牲性能。通过所有权、借用和生命周期机制,Rust避免了空指针和数据竞争等问题,简化了并发编程。相较于C/C++,Rust在编译时预防内存错误,提供类似C++的语法和更高的安全性。Rust适用于系统编程、WebAssembly、嵌入式系统和工具开发等领域。其生态系统包括Cargo包管理器和活跃社区。学习资源如&quot;The Book&quot;和&quot;Rust by Example&quot;帮助新手入门。安装Rust可通过Rustup进行,支持跨平台操作。
160 2
初探 Rust 语言与环境搭建