<The Rust Programming Language> 配套视频(第8章-第9章)

内容来自杨旭老师 Rust编程语言入门教程(Rust语言/Rust权威指南配套)【已完结】



第8章 通用集合类型

使用动态数组(Vector)存储多个值

创建动态数组

更新动态数组

销毁动态数组时也会销毁其中的元素

读取动态数组中的元素

遍历动态数组中的值

使用枚举来存储多个类型的值

使用字符串存储UTF-8编码的文本

字符串是什么

创建一个新的字符串

更新字符串

字符串索引

字符串切片

遍历字符串的方法

字符串的确没那么简单

使用哈希映射中存储键值对

创建一个新的哈希映射

哈希映射与所有权

访问哈希映射中的值

更新哈希映射

哈希函数



第9章 错误处理

不可恢复错误与panic!

使用panic!产生的回溯信息

可恢复错误与Result

匹配不同的错误

失败时触发panic的快捷方式:unwrap和expect

传播错误

要不要使用panic!

示例、原型和测试

当你比编译器拥有更多信息时

错误处理的指导原则

创建自定义类型来进行有效性验证

!!!











!!!

!!!

在 Rust 中,OsStringOsStrCStringCStr 都是用于处理不同类型的字符串和字符序列的类型。

  1. OsStringOsStr

    • OsString 是一个可拥有不同平台原生字符串表示的可变字符串类型。它可以包含任意有效的 Unicode 字符序列,并且可以自动适应不同的操作系统。
    • OsStr 是一个不可变的字符串切片类型,它对应于 OsString。它提供了对 OsString 中存储的字符串进行引用的功能。

    这些类型的目的是为了在操作系统之间提供一致的字符串处理,以便在不同平台上编写可移植的代码。

  2. CStringCStr

    • CString 是一个在 Rust 中表示以 null 字节结尾的 C 字符串的类型。它是一个可拥有不同平台原生字符串表示的可变字符串类型,类似于 OsString。它提供了将 Rust 字符串转换为 C 字符串的功能。
    • CStr 是一个在 Rust 中表示以 null 字节结尾的不可变 C 字符串的类型。它对应于 CString,提供了对 CString 中存储的 C 字符串进行引用的功能。

    这些类型主要用于与 C 代码进行交互,特别是在调用 C 函数或与 C 库进行交互时,需要将 Rust 字符串转换为 C 字符串或引用 C 字符串。

通过使用这些类型,Rust 提供了灵活且安全地处理不同类型的字符串和字符序列的功能,同时也支持与操作系统和 C 代码的交互。

Rust中 使用push_str和+ 连接字符串有何区别?哪个性能更好

Rust中有两种主要方式来连接字符串:

  1. 使用push_str方法在一个现有的String上追加另一个字符串。

  2. 使用+操作符连接两个字符串生成一个新的String

两者的主要区别在于:

  • push_str直接在原字符串上修改,不需要重新分配内存。这样更加高效,特别是在追加多个字符串的时候。

  • +操作符会重新分配内存并复制字符串内容,生成一个新的String。这在连接少量字符串时可以接受,但连接大量字符串会产生很多无用的内存分配和数据复制。

所以从性能角度来说,push_str通常要比+操作符更快,特别是追加大量字符串的时候。

但是+操作符的语义更清晰,代码也更简洁。在连接少量字符串时,使用+操作符可以提高代码可读性。

总结一下:

  • 追加大量字符串时优先考虑push_str,可以显著提高性能
  • 连接少量字符串时,使用+操作符可以获得更好的可读性
  • 在追求性能关键的代码里,建议主要使用push_str rather than +

所以在Rust中连接字符串时需要权衡性能和可读性,根据具体情况选择最合适的方式。

!!!








!!!

在Rust中,表示字符串的三种主要形式是:

  • Bytes(字节)
  • Scalar Values(标量值)
  • Grapheme Clusters(字形集群)

它们之间的主要区别是:

  1. 字节(Bytes)
  • 是字符串的最基本单位,每个字节代表一个u8的值
  • 在Rust中通常用&[u8]Vec<u8>表示
  • 对应中文中的“字节”
  1. 标量值(Scalar Values)
  • 表示一个Unicode中的代码点(code point)
  • 在Rust中通常用char类型表示
  • 对应中文中的“码点”
  1. 字形集群(Grapheme Clusters)
  • 表示人类可读的最小单位
  • 一个字形集群可能包含多个标量值组合而成
  • 在Rust中通常用&str表示
  • 对应中文中的“字符”

举个例子:

字节:[229, 165, 189]

标量值:'国'

字形集群:"国"

汉字“国”包含3个字节,1个标量值,1个字形集群。

所以在Rust中正确处理字符串需要明确这三者的区别和联系。


能否举一个例子来说明如何在Rust中处理字符串的字节、标量值和字形集群?

好的,这里给一个具体的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let s = "Hello 国";

// 以字节访问
let bytes = s.as_bytes();
println!("Bytes: {:?}", bytes);

// 以标量值访问
let scalars: Vec<char> = s.chars().collect();
println!("Scalars: {:?}", scalars);

// 以字形集群访问
let graphemes = s.graphemes(true).collect::<Vec<&str>>();
println!("Graphemes: {:?}", graphemes);
}

输出:

1
2
3
Bytes: [72, 101, 108, 108, 111, 32, 229, 165, 189]
Scalars: ['H', 'e', 'l', 'l', 'o', ' ', '国']
Graphemes: ["Hello", " ", "国"]

这里演示了以下内容:

  • as_bytes() 方法可以将字符串视为字节序列
  • chars() 方法可以遍历字符串的标量值
  • graphemes() 方法可以按字形集群切分字符串

另外要注意chars()graphemes() 的区别:

  • chars() 会将组合字符(如一些表情符号)拆分成多个标量值
  • graphemes() 会将它们保持为一个字形集群

这就体现了标量值和字形集群的区别。

所以在Rust中需要根据具体的处理需求来选择使用字节、标量值还是字形集群来访问字符串。


这三者分别对应Go语言的什么?举例说明

在Go语言中,字符串相关的主要类型对应Rust的字节、标量值和字形集群如下:

  • 字节(Bytes)

Go中的[]byte对应Rust的字节操作。例如:

1
2
s := "Hello 国"
bytes := []byte(s)
  • 标量值(Scalar Values)

Go中的rune类型对应Rust的char。可以这样迭代:

1
2
3
for _, r := range s {
// r 为 rune 类型
}
  • 字形集群(Grapheme Clusters)

Go中直接使用string即可,因为它以UTF-8编码存储。例如:

1
chars := []string{s[0], s[1], s[2]} // 按字形集群切分

另外Go中的字符串是不可变的,所以没有Rust中的push_str等方法。

总结一下对比:

Rust Go
Vec<u8> []byte
char rune
&str string

所以Go语言内置了这三种字符串表示,和Rust的处理思路是一致的。

!!!







在Rust中,collect()是Iterator trait中一个很重要的方法。它的主要作用是:

将一个Iterator转换成一个集合类型(Collection)。

Iterator在Rust中是一种延迟计算(lazy)的抽象,它代表一个元素序列,但需要调用collect()等方法才会真正开始执行计算。

collect()会消费掉整个Iterator,把结果存入一个集合类型中,常见的如Vec、HashSet等。

举个例子:

1
2
3
4
5
6
7
let v = vec![1, 2, 3];

let iter = v.iter(); // 创建一个迭代器

let vec: Vec<&i32> = iter.collect(); // 收集为Vec

println!("{:?}", vec); // [1, 2, 3]

这里从一个Vec创建了一个迭代器iter,然后调用collect,将迭代器的元素收集为一个新的Vec。

collect()非常强大,它可以将迭代器收集为任意的集合类型,包括Vec、HashSet、String等。

另一个例子是从Iterator收集为String:

1
2
3
4
5
6
let s = [1, 2, 3]
.iter()
.map(|x| x.to_string())
.collect::<String>();

println!("{}", s); // "123"

这里通过collect将一个数字迭代器,收集为一个字符串。

总结一下collect的主要作用:

  • 消费迭代器,强制执行迭代操作
  • 收集迭代器的结果为集合类型,如Vec、HashSet等
  • 非常灵活,可以支持多种集合类型

它是Rust中将迭代器转换为集合的主要方式之一。

!!!














Go的ok判别式

!!!

!!!

!!!