rust语言基础学习: rust中的字符串
2020-07-04
在Rust中提到字符串,通常指的是rust核心语言中的字符串类型str
(字符串slice)和rust标准库中的String
类型。
除了str
和String
这两个常用的字符串类型,在标准库中还有一些其他的字符串类型,例如OsString
、OsStr
、CString
、CStr
。
本文将介绍str
和String
两个字符串类型。
str字符串slice #
str
是rust核心语言中内置的字符串类型,它通常以"借用"&str
的形式出现,str即字符串slice,是一些存储在别处的UTF-8编码的字符串数据的引用。
例如编写的rust代码中的字符串字面值被存储在程序的二进制中。
在学习str
之前,先看一下slice类型。slice是rust中没有所有权
的数据类型之一,使用slice可以引用集合中一段连续的元素序列,而不用引用整个集合。
字符串slice是String
中一部分值的引用,例如:
1fn main() {
2 let s = String::from("hello world");
3 let hello = &s[..5];
4 let mid = &s[4..7];
5 let world = &s[6..];
6 println!("{}", hello); // "hello"
7 println!("{}", mid); // "o w"
8 println!("{}", world); // "world"
9}
rust中slice的语法是使用[start_index..end_index]
指定的范围创建一个slice,包含start_index
处的元素,而不包含end_index
处的元素,rust中切片slice划得的元素个数是end_index - start_index
(在这点上与go语言中的slice十分相似)。
需要注意字符串slice指定范围边界的索引必须是有效的UTF-8字符串边界,如果从一个多字节字符的中间位置创建字符串slice,程序将会panic(在这点上与go语言对string类型进行切片操作是不同的,在go中不会panic)。例如:
1fn main() {
2 let s = String::from("你好 世界");
3 let hello = &s[..1]; // thread 'main' panicked at 'byte index 1 is not a char boundary; it is inside '你' (bytes 0..3) of `你好 世界`'
4 println!("{}", hello);
5}
前面声明字符串slice时是使用的类型字段推断,还需要知道字符串slice的类型声明是&str
,例如:
1fn main() {
2 let s = String::from("hello world");
3 let hello :&str = &s[..5];
4 println!("{}", hello);
5}
字符串字面值实际上就是字符串slice:
1let hello :&str = "hello";
上面代码中的hello
变量的类型是&str
,它是一个指向二进制程序特定位置的字符串slice,&str
是一个不可变引用,字符串字面值是不可变的。
String是一种集合类型 #
Rust中的字符串String
是以字节集合加上一些方法实现的。
可以认为String
是一种集合类型,支持集合类型常见增删改查操作。
String
类型由Rust的标准库提供,是可变的、有所有权的、以UTF-8编码字符串数据的引用。
使用String类型的new
函数,可以创建一个空的字符串,调用push_str
方法可以向其中添加字符串slice:
1fn main() {
2 let mut s = String::new();
3 s.push_str("hello");
4 s.push_str(" ");
5 s.push_str("world");
6 println!("{}", s);
7}
rust中的String类型字符串不支持索引访问,例如s[0]
会出现编译错误。
如果去查看String
类型源码的话,会发现它实际上是一个Vec<u8>
的封装:
1pub struct String {
2 vec: Vec<u8>,
3}
4....
可以看出String
类型是字节vector加上一些方法实现的。
遍历字符串 #
rust字符串UTF-8编码的特性,决定了有两种遍历字符串的方式,以字符形式和以字节形式。
1fn main() {
2 let s = "你好";
3 for c in s.chars() {
4 print!("{}, ", c) // 你, 好,
5 }
6 println!();
7 for s in s.bytes() {
8 print!("{}, ", s) // 228, 189, 160, 229, 165, 189,
9 }
10}