Rust 探索(六)—— 所有权(三)

1. 切片

除引用外,还有另外一种不持有所有权的数据类型——切片

切片允许我们引用集合中某一段连续的元素序列

2. 字符串切片

字符串切片是指向String对象中某个连续部分的引用

1
2
3
4
let s = String::from("hello world");

let hello = &s[0..5];
let world = &s[6..11];

切片的写法类似于引用,不过不是整体,而是一段连续区域,对应元素索引的左闭右开区间

image-20230421234537818

1
2
3
4
5
 let s = String::from("hello world");

let hello = &s[..5]; // [0, 5)
let world = &s[6..]; // [6, 11)
let hello_world = &s[..]; // [0, 11)

字符串切片类型表示为&str

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let s = String::from("hello world");
let result = match_str(&s);
println!("{}", result);
}

fn match_str(parent: &String) -> &str { // 返回类型为切片
let bytes = parent.as_bytes();
for (index, &item) in bytes.iter().enumerate() {
if item == b' ' { // 匹配到空格,返回前面的hello
return &parent[0..index];
}
}
&parent
}

2.1. &str类型

字符串切片使得代码编写更加安全

编译器会确保指向String的引用持续有效

在默认的情况下,切片也是不可变引用,因此这就会带来约束,可变与不可变的互斥,将其作为不可变时,任何修改内容的操作,如:clear(),都能在编译时被及时发现

2.2. 字面量就是切片

前面可以看到,我们使用字符串字面量时都是使用String::from()声明,那么其本身是什么类型呢?

1
let s = "hello world";

image-20230422114458580

实际上是&str,也就是字符串切片类型,并且这是一个不可变引用

在定义函数的时候使用字符串切片代替字符串引用会使API更加通用,并且不会损失任何功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
let s = String::from("hello world");

let result = match_str(&s);
println!("{}", result);
}

fn match_str(parent: &str) -> &str { // 修改入参的类型为字符串切片
let bytes = parent.as_bytes();
for (index, &item) in bytes.iter().enumerate() {
if item == b' ' { // 匹配到空格,返回前面的hello
return &parent[0..index];
}
}
&parent
}

3. 其他类型的切片

切片并非字符串专属,其他类型也可以使用切片特性

1
2
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3]; // 数组切片 &[i32]