Slice类型
Slice
数据类型没有所有权,slice
允许我们引用集合中一段连续的元素序列而不用引用整个集合。字符串slice(string slice) 是String
中 一部分值的引用。如下述代码示例,不是对整个String
的引用而是对部分String
的引用:
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
}
可以使用一个由中括号中的 [starting_index..ending_index]
指定的 range 创建一个 slice,其中 starting_index
是 slice 的第一个位置,ending_index
则是 slice 最后一个位置的后一个值。在其内部,slice 的数据结构存储了 slice 的开始位置和长度,长度对应于 ending_index
减去 starting_index
的值。所以对于 let world = &s[6..11];
的情况,world
将是一个包含指向 s
第 7 个字节(从 1 开始)的指针和长度值 5 的 slice。如下图所示:
对于 Rust 的 ..
range 语法,如果想要从第一个索引(0)开始,可以不写两个点号之前的值。同样的,如果 slice 包含 String
的最后一个字节,也可以舍弃尾部的数字。如下代码:
// 舍弃开头数字
fn main() {
let s = String::from("hello");
let slice = &s[0..2];
let slice = &s[..2];
}
// 舍弃尾部数字
fn main() {
let s = String::from("hello");
let len = s.len();
let slice = &s[0..len];
let slice = &s[..];
}
字符串字面值
现在我们知道了Slice
,就可以正确的理解字符串字面值了。这里 s
的类型是 &str
:它是一个指向二进制程序特定位置的 slice。这也就是为什么字符串字面值是不可变的;&str
是一个不可变引用。
let s = "hello rust";
其他类型的slice
字符串 slice,是针对字符串的。不过也有更通用的 slice 类型,比如数组(array),就和获取一部分字符串一样,如果我们想要引用数组的一部分,也可以和字符串slice一样的操作。
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
这个slice
变量的类型是&[i32]
,它跟字符串 slice 的工作方式一样,通过存储第一个集合元素的引用和一个集合总长度。你可以对其他所有集合使用这类 slice。
总结
所有权系统影响了 Rust 中很多其他部分的工作方式。所有权、借用和 slice 这些概念让 Rust 程序在编译时确保内存安全。Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存,但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码。