58、Slices(切片)

Slices(切片)

 

让我们回顾一下Vec的内存布局:

let mut numbers = Vec::with_capacity(3);
numbers.push(1);
numbers.push(2);

Vec内存布局

 

我们之前学到了String本质上其实就是Vec<u8>,从中可以衍生出一个问题:Vec&str等价于什么?

 

&[T]

 

[T]是T类型元素的连续序列的切片。

它最常以借用形式&[T]使用。

 

有多种方式可以从Vec创建切片引用:

let numbers = vec![1, 2, 3];
// Via index syntax 通过索引语法
let slice: &[i32] = &numbers[..];
// Via a method 通过方法
let slice: &[i32] = numbers.as_slice();
// Or for a subset of the elements 或对于元素的子集
let slice: &[i32] = &numbers[1..];

 

Vec 使用 [T] 作为目标类型实现了 Deref trait,因此得益于 Deref 强制转换,我们可以直接对 Vec 使用切片(slice)方法。

let numbers = vec![1, 2, 3];
// Surprise, surprise: `iter` is not a method on `Vec`!
// It's a method on `&[T]`, but you can call it on a `Vec` 
// thanks to deref coercion.
// 令人惊讶的是:iter 并不是 Vec 上的方法!
// 它实际上是 &[T] 上的方法,但你可以通过 Deref 强制转换在 Vec 上直接调用它。
let sum: i32 = numbers.iter().sum();

怪不得,我之前在Vec里面找iter()方法找不到呢

 

内存布局

 

&[T]是一个胖指针,就像&str一样。

它由指向切片的第一个元素的指针和切片的长度组成。

 

如果我们有一个包含三个元素的Vec

let numbers = vec![1, 2, 3];

然后创建一个切片引用:

let slice: &[i32] = &numbers[1..];

我们就可以得到这样的内存布局:

切片的内存布局

 

&Vec<T> vs &[T]

 

当我们需要向函数传递一个不可变的Vec引用时,首选&[T]而不是&Vec[T]

这允许函数接受任何类型的切片,而不一定是由Vec支持的切片。

 

例如,我们可以传递Vec中元素的子集。但他远不止于此——我们还可以传递Array的切片:

let array = [1, 2, 3];
let slice: &[i32] = &array;

Array切片和Vec切片是同一种类型:他们都是指向连续元素序列的胖指针。在arrays的情况下,指针指向堆栈(stack)而不是堆(heap),但在使用切片时,这并不重要。

 

练习

 

这一节的练习比较简单:

// TODO: Define a function named `sum` that takes a reference to a slice of `u32` and returns the sum of all
//  elements in the slice.
// TODO:定义一个名为 sum 的函数,该函数接受一个 u32 切片的引用,并返回切片中所有元素的总和。

pub fn sum(num:&[u32])->u32{
    num.iter().sum()
}

 

就是让我们实现一个函数,函数接受一个u32类型的切片,然后返回所有元素的总和,我们使用迭代器和组合器就可以完成那些逻辑,其他的也没有什么很难的地方。

 

这一节就先到这里了。

阅读剩余
THE END