第8章 字符串与集合

 

本文简介

本文简介

第8章 字符串与集合

程序中最常用的三大数据结构是字符串、数组和射。

字符串和数组、映射的区别在于,字符串是被作为一个整体来关注和使用的; 数组和映射关注最多的是其中的元素及它们之间的关系。所以,数组和映射也被称为集合类型。

8.1 字符串

  • 字符和计算机底层一串01的一一映射关系就叫作字符编码(Character Encoding) 。
  • Unicode字符集是通用的多字节编码字符集集。Unicode 字符集相当于一张表,其中包含了世界上所有语言中可能出现的字符,每个字符对应一个非负整数,该数字称为码点(Code Point) 。这个码点也分为不同的类型,包括标量值(Scala Value) 、代理对码点、非字符码点、保留码点和私有码点。
  • 标量值最常用,它是指实际存在对应字符的Unicode码位
  • Unicode只规定字符对应的码点,没有指定如何存储
  • Unicode 字符集解决了字符通用的问题,但是必须寻求另外一种存储方式以更加节约流量和硬盘空间。这种存储方式就是码元(Code Unit)组成的序列
  • 码元是指用于处理和交换编码文本的最小比特组合。比如计算机处理字符的最小单位1字节就是一个码元。通过将Unicode标量值和码元序列建立一一映射关系,就构成了编码表
  • Unicode中一共有三种这样的字符编码表:UTF-8、UTF-16 UTF-32,它们正好对应了1字节、2字节和4字节的码元。
  • 但是多字节码元有字节序的问题,而UTF-8一个码元只有一个字节,不存在字节序可以直接储存
  • UTF-8编码规则大致如下:
    • 当一个字符在ASCII码的范围(兼容ASCII码)时,就用1字节表示
    • 当一个字符占用了n个字节时,第一字节的前n个设置为1,第n+1位设置为0,后面字节的前两位设置为10
  • Unicode字符转换为字节序列的过程称为编码;把编码字节序转为字符的过程为解码

8.2 字符

  • Rust使用char类型表示单个字符。char类型使用整数值与Unicode标量值一一对应
  • Rust用单引号来定义字符,使用双引号定义的是字符串字面量。
  • 在Rust中每个char类型的字符都代表一个有效的u32类型的整数
  • 为了能存储任何Unicode标量值,Rust规定每个字符都占4个字节
方法 说明
is_digit(16) 用于判断给定字符是否属于十六进制形式。如果参数为10,则判断是否为十进制形式
to_digit(16) 用于将给定字符转换为十六进制形式。如果参数为10,则将给定字符转换为十进制形式
is_lowercase 用于判断给定字符是否为小写的。作用于 Unicode 字符集中具有Lowercase属性的字符
is_uppercase 用于判断给定字符是否为大写的。作用于 Unicode 字符集中具有Uppercase属性的字符
to_lowercase 用于将给定字符转换为小写的。作用于Unicode字符集中具有Lowercase属性的字符
to_uppercase 用于将给定字符转换为大写的。作用于Unicode字符集中具有Uppercase属性的字符
is_whitespace 用于判断给定字符(或十六进制形式的码点)是否为空格字符
is_alphabetic 用于判断给定字符是否为字母。汉字也算是字母
is_alphanumeric 用于判断给定字符是否为字母、数字
is_control 用于判断给定字符是否为控制符
is_numeric 用于判断给定字符是否为数字
escape_default 用于转义\t\r\n、单引号、双引号、反斜杠等特殊符号

8.3 字符串分类

类别 说明
str 表示固定长度的字符串
String 表示可增长的字符串
CStr 表示由C分配而被Rust借用的字符串,一般用于和C语言交互
CString 表示由Rust分配且可以传递给C函数使用的C字符串,同样用于和C语言交互
OsStr 表示和操作系统相关的字符串。这是为了兼容Windows系统
OsString 表示OsStr的可变版本。与Rust字符串可以相互转换
Path 表示路径,定义于std::path模块中。Path包装了OsStr
PathBuf 跟Path配对,是Path的可变版本。PathBuf包装了OsString

创建字符串的各种方法:

let string = String::new();
let string = String::from("hello rust");
let string = String::with_capacity(20);

let str = "hello";
let string = str.chars().filter(|c| !c.is_whitespace()).collect();
let string = str.to_owned();
let string = str.to_string();

8.1.4 字符串的两种处理方式

在Rust中对字符串的操作大致分为两种方式:按字节处理和按字符处理 。

  • let str = "boo虎foo"
    • 如何得到字符串的长度?长度是多少?长度的单位是___数
    • 如何将其转换为字符char向量,它的长度是多少?
    • 如何将其转换为字符bytes迭代器?
  • 字符串为什么不能按索引访问其中字符?
  • let mut v = String::from("boo虎foo");
    • 如何访问第0个字符?
    • 如何访问”虎”这个字符?
    • v.get_mut(5..)的结果是什么?
    • 如何判断字符”虎”的边界是3?
  • let s = "hello,我的世界";
    • 如何分割成中英文两个子串?
    • 在索引7处分割可以吗?

8.1.5 字符串的修改

修改字符串,则使用String类型。修改字符串大致分为追加、插入、连接、更新和删除5种情形

  1. 追加
      let mut hello = String::from("Hello, ");
    
    • 如何在hello后追加一个字符R
    • 如何追加字符串ust!
    • 如何通过Extend迭代器追加字符串
    • 为什么hello可以通过extend追加字符串
    • 如何通过迭代器追加[',', 'r', 'u']数组
    • 如何通过迭代器追加"st "字符串
    • 如何通过迭代器追加"w o r l d"去除空白字符的字符串
  2. 插入字符串
      let mut s = String::with_capacity(3);
    
    • 如何在索引0处插入'f'字符
    • 如何在索引2处插入'o'字符(对吗?)
    • 如何在索引0处插入"bar"字符串
    • 索引的单位是_____
    • insert内部是基于is_char_boundary来判断插入位置的合法性的
  3. 连接字符串
      let left = "abc".to_string();
      let right = "def".to_string();
    
    • 如何把leftright连接起来
  4. 更新字符串
      let s = String::from("foobarr");
    
    • 如何把偶数位改成大写?
  5. 删除字符串
      let mut s = String::from("He虎llo");
    
    • 如何删除”虎”字?
    • 如何删除最后一个字符?
    • 如何删除虎后面的所有字符?
    • 如何清除整个字符串?
        let mut s = String::from("老虎 is tiger, 山羊 is sheep");
      
    • drain的作用:移除指定范围内的字符串?
    • 如何用drain把字符串分成两个部分?

8.1.6 字符串的查找

rust 可以用字符匹配的方法来查找

分类 方法
存在性判断 contains、starts_with、ends_with
位置匹配 find、rfind
分割字符串 split、rsplit、split_terminator、rsplit_terminator、splitn、rsplitn
捕获匹配 matches、rmatches、match_indices、rmatch_indices
删除匹配 trim_matches、trim_left_matches、trim_right_matches
替代匹配 replace, replacen

字符串匹配模式原理

matches

8.1.7 与其他类型的互换

  • 如何把&str类型转换为u32类型?
    • parse方法内部是用__trait的___方法来实现的?
    • 如何实现下面的代码:
      struct Point {x: i32, y: i32};
      let p = Point::from_str("{1, 2}");
      assert_eq!(p.unwrap(), "Point{x: 1, y: 2}");
      
  • 把其他类型转为字符串用____宏?
    • format!宏使用的是__trait中的__函数
  • 用什么关键字保留字符串中的特殊符号?

8.2 集合类型

类型 说明
Vec<T> 变长数组
VecDeque<T> 双端队列
LinkedList<T> 双向链表
BinaryHeap<T> 二叉堆(最大堆)
HashMap<T> 哈希表
BTreeMap<T> 基于B树的有序映射集
HashSet<T> 无序集合
BTreeSet<T> 有序集合

8.2.1 变长数组

  • array元素可以保存在__上,而Vec元素只能在__上
  • String类型是____的包装
  • Rust用____值代表零大小的容量
  • Rust的偏序、全序与等价
    • 偏序与全序相差的是_____
    • 完全性是指的这个类型的每个元素都可以____
    • PartialEq定义了__和__两个方法
    • Eq表示标记了Eq的类型是___关系

Vec的基本操作

操作 方法
新建 Vec::new()
压栈 vec.push(1)
长度 vec.len()
索引 vec[0]
弹出 vec.pop()
改写 vec[0] = 7
获取 vec.get(10)
扩展 vec.extend([1, 2, 3].iter().cloned())
获取 vec.get(1..2)
转移 vec.append(&mut vec1)
交换 vec.swap(1, 3)
拷贝 vec.copy_from_slice(&[1, 2, 3])
拷贝 vec.clone_from_slice(&[1, 2, 3])
截断 vec.truncate(0)
清零 vec.clear()
释放 vec.shrink_to_fit()
包含 vec.contains(&10)
起始 vec.starts_with(&[10])
起始 vec.starts_with(&[10, 20])
结束 vec.ends_with(&[30])
结束 vec.ends_with(&[20, 30])
结束 vec.ends_with(&[])
搜索 vec.binary_search(&10)
搜索 vec.binary_search_by(|p| p.com(&13))
排序 vec.sort(), vec.sort_by(), vec.sort_by_key()

8.2.2 映射集

Map是依照__形式存储的数据结构,Rust有两种类型的Map:基于Map、基于__Map

HashMap的增、删、改、查

操作 说明
创建 books = HashMap::with_capacity(10)
插入 books.insert("Rust Book", "good")
循环 for key in books.keys()
  for val in books.values()
包含 books.contains_key("Rust Book")
删除 books.remove("Rust Book")
获取 books.get("Rust Book")
迭代 for (book, review) in &books
索引 books["Rust Book"]

Entry的方法

Entry体有三个方法or_insertor_insert_withkey,需要先把HashMap转为___

对于

let mut map: HashMap<&str, u32> = HashMap::new();
  • 找到current_year项,没有就增加并插入2017
  • 找到current_year项的可变引用,并给它的值加10
  • 找到current_year项,没有就用环境变量next_year+10给它赋值
操作 说明
创建 let mut map: HashMap<&str, i32> = HashMap::new()
查询或创建 map.entry("current_year").or_insert(2021)
查询或修改 *map.entry("current_year").or_insert(2021) += 10
  map.entry("current_year").or_insert_with(|| last_year + 10)

Map合并的方法

  • extend合并
    map1.extend(map2)
    
  • merge_chain合并
    map1.into_iter().chain(map2).collect()
    
  • merge_by_ref合并
    map1.extend(map_ref.into_iter().map(|(k, v)| (k.clone(), v.clone())))
    

    Hash碰撞的两个元素称为____

8.3 容量

容量是为集合容量分配的__空间,其大小是指集合包含的__数量