Rust入坑指南:鳞次栉比
很久没有挖Rust的坑啦,今天来挖一些排列整齐的坑。没错,就是要介绍一些集合类型的数据类型。“鳞次栉比”这个标题是不是显得很有文化?
在Rust入坑指南:常规套路一文中我们已经介绍了一些基本数据类型了,它们都存储在栈中,今天我们重点介绍3种数据类型:string,vector和hash map。
String
String类型我们在之前的学习中已经有了较多的接触,但是没有进行过详细的介绍。有些有编程基础的同学可能不屑于学习String类型,毕竟它在所有编程语言中可以说是最常用的类型了,大家也都很熟悉了。对于有这种心理的同学,我想对他们说:我刚开始也是这样想的,直到后来我被编译器揍的满头包,才下定决心回来认真学习一下String类型。
Rust的字符串分为以下几种类型:
- str:表示固定长度的字符串
- String:表示可增长的字符串
- CStr:表示由C分配,被Rust借用的字符串,一般用于和C语言交互
- CString:表示由Rust分配并且可以传递给C语言的字符串
- OsStr:表示和操作系统相关的字符串,主要为了兼容Windows
- OsString:OsStr的可变版本
- Path:表示路径
- PathBuf:是Path的可变版本
本文我们重点讨论前两种,因为它们是开发过程中最常用的,也是比较容易混淆的。对于str,我们常见的是它的引用类型,&str
。如果你看过了Rust入坑指南:核心概念一文后,相信你已经了解了引用类型和Ownership的概念。也就是说String类型具有Ownership而&str没有。
在Rust中,String本质上是Vec<u8>,Vec是向量集合的关键字,我们在后面会介绍。String类型由三个部分组成,分别是:指向堆中字节序列的指针,记录堆中字节序列的长度和堆分配的容量。通过一段代码也许你很有更深的理解。
fn main() { let mut a = String::from("foo"); println!("{:p}", a.as_ptr()); println!("{:p}", &a); assert_eq!(a.len(), 3); a.reserve(10); assert_eq!(a.capacity(), 13); }
在这段代码中我们可以看到,a.as_ptr()获取指针和&a获取的指针是不一样的。
这里我们解释一下,as_ptr获取到的指针是堆中字节序列的指针地址,而&a的地址是字符串变量在栈上的指针地址。另外,len()和capacity()方法得到的长度都是字节数量,而非字符数量。这里你可以自己动手试试中文字符的长度。
聊完了字符串的基本概念以后,相信你已经对Rust的字符串有了一个大概的认识。接下来我们就一起来看一看字符串的CRUD的方法吧。
创建字符串
话不多说,先来展示一下创建字符串的各种方法。
fn main() { let string: String = String::new(); let string: String = String::from("hello rust"); let string: String = String::with_capacity(10); let str: &'static str = "Jackey"; let string: String = str.to_owned(); let string: String = str.to_string(); }
我们比较常用的是前两种,下面介绍一下后面几个方法。with_capacity()是创建一个空字符串,参数表示在堆中分配的字节数。to_owned和to_string是演示了如何把&str类型转换成String类型。
修改字符串
Rust修改字符串的常用方法也有很多,例如在字符串后追加,连接两个字符串,更新字符串等。下面这段代码就展示了一些修改字符串的方法。
fn main() { let mut hello = String::from("Hello, "); hello.push('J'); // 追加单个字符 hello.push_str("ackey! "); //追加字符串 println!("push: {}", hello); hello.extend(['M', 'y', ' '].iter()); //追加多个字符,参数为迭代器 hello.extend("name".chars()); println!("extend: {}", hello); hello.insert(0, 'h'); //类似于push,可以指定插入的位置 hello.insert(1, 'a'); hello.insert(2, '!'); hello.insert_str(0, "Haha"); println!("insert: {}", hello); let left = "Hello, ".to_string(); let right = "World".to_string();