Array-Vec-Slice

Array是一种线性的容器,储存同一种类型的数据,而其长度在生成后即固定下来,在内存中是连续而紧密排列的,好处在于可快速存取数据,Array是透过索引值存取数据,但当要改变长度时,效率则较差,因为要复制Array中的数据

  1. //创建
  2. let mut array: [i32; 3] = [0; 3]; // 方式一
  3. let arr = [8,9,10]; // 方式二
  4. //修改
  5. array[1] = 1;
  6. array[2] = 2;
  7. for x in &array {
  8. print!("{} ", x);
  9. }

Rust的数组中的N(大小)也是类型的一部分,即[u8; 3] != [u8; 4]

  1. extern crate rand;
  2. use rand::Rng;
  3. fn main() {
  4. const SIZE: usize = 10;
  5. let mut array = [0; SIZE];
  6. for i in 0..array.len() {
  7. // Set a random number between 1 and 100
  8. array[i] = rand::thread_rng().gen_range(1, 100 + 1);
  9. }
  10. }

或是使用迭代器,

  1. fn main() {
  2. let array = ["eins", "zwei", "drei", "vier", "fünf"];
  3. for element in array.iter() {
  4. println!("{}", element);
  5. }
  6. }
  7. //-----------------------------
  8. extern crate rand;
  9. use rand::Rng;
  10. fn main() {
  11. const SIZE: usize = 100;
  12. let mut array = [0; SIZE];
  13. for e in array.iter_mut() {
  14. *e = rand::thread_rng().gen_range(1, 100 + 1);
  15. }
  16. }

目前 Rust 的Array有一些使用上的限制,某些函数在Array长度大於 32 時无法使用。

这些 trait 的大小限制是 Rust 內部实现问题,而不是Array的正常行為,Rust 官方提到这个问题。在 Rust 改善前,有几种处理方式,包括:

  • 自行实现相关trait
  • 避免使用这些方法
  • 改用Vec

(1) 不是通用的方法,因为针对每个长度,都要重新一次,但若有需求,仍可考慮;(2) 会限制了Array的使用场合;通常可考慮 (3)。

Vec

Vec 是一个动态或“可变”的数组容器,其內部实现也是Array,但可动态增加长度。向量在增減长度時有数据的拷贝,大量数据搬移的需求,可考虑其他容器。Vec具有动态的添加和删除元素的能力,并且能够以O(1)的效率进行随机访问。同时,对其尾部进行push或者pop操作的效率也是平摊O(1)的。Vec的所有内容项都是生成在堆空间上,你可以轻易的将Vec move出一个栈而不用担心内存拷贝影响执行效率——毕竟只是拷贝的栈上的指针。

Vec<T>中的泛型T必须是Sized的,也就是说必须在编译的时候就知道存一个内容项需要多少内存。对于那些在编译时候未知大小的项(函数类型等),我们可以用Box将其包裹,当成一个指针。

  1. let v1: Vec<i32> = Vec::new(); // 方式一
  2. let v = vec![1, 2, 3, 4, 5]; // 方式二
  3. let v2 = vec![0;10]; //声明一个初始长度为10的值全为0的动态数组

从迭代器生成

因为Vec实现了FromIterator这个trait,因此,借助collect,我们能将任意一个迭代器转换为Vec。

  1. let v: Vec<_> = (1..5).collect();
  2. let mut v2 = (0i32..5).collect::<Vec<i32>>();

使用枚举来储存多种类型

  1. enum SpreadsheetCell {
  2. Int(i32),
  3. Float(f64),
  4. Text(String),
  5. }
  6. let row = vec![
  7. SpreadsheetCell::Int(3),
  8. SpreadsheetCell::Text(String::from("blue")),
  9. SpreadsheetCell::Float(10.12),
  10. ];

访问元素

为了Vec特定索引的值,我们使用[],索引从0开始.

  1. let v = vec![1, 2, 3, 4, 5];
  2. let r0 = v[1];
  3. let r1 = &v[2]; //当引用一个不存在的元素时,会造成panic!.
  4. let r2 = v.get(3); //当引用一个不存在的元素时,返回None.
  5. println!("The third element of v is{}, {},{}", r0, r1,r2);
  6. fn main() {
  7. let vec = vec![1, 2, 3];
  8. for i in 0..(vec.len()) {
  9. println!("{}", i);
  10. }
  11. }
  12. //--------------------------
  13. fn main() {
  14. let vec = vec![1, 2, 3];
  15. for element in vec.iter() {
  16. println!("{}", element);
  17. }
  18. }
  19. //----------------------------
  20. fn main() {
  21. let mut vec = vec![1, 2, 3];
  22. for i in 0..vec.len() {
  23. vec[i] = vec[i] * vec[i];
  24. }
  25. assert_eq!(vec[0], 1);
  26. assert_eq!(vec[1], 4);
  27. assert_eq!(vec[2], 9);
  28. }
  29. //----------------------------
  30. fn main() {
  31. let mut vec = vec![1, 2, 3];
  32. for element in vec.iter_mut() {
  33. *element = (*element) * (*element);
  34. }
  35. assert_eq!(vec[0], 1);
  36. assert_eq!(vec[1], 4);
  37. assert_eq!(vec[2], 9);
  38. }

另外值得注意的是你必须用usize类型的值来索引:

  1. let v = vec![1, 2, 3, 4, 5];
  2. let i: usize = 0;
  3. let j: i32 = 0;
  4. // works
  5. v[i];
  6. // doesn’t
  7. v[j];

用非usize类型索引的话会给出类似如下的错误:

  1. error: the trait `core::ops::Index<i32>` is not implemented for the type
  2. `collections::Vec::Vec<_>` [E0277]
  3. v[j];
  4. ^~~~
  5. note: the type `collections::Vec::Vec<_>` cannot be indexed by `i32`
  6. error: aborting due to previous error

随机访问

就像数组一样,因为Vec借助IndexIndexMut提供了随机访问的能力,我们通过[index]来对其进行访问,当然,既然存在随机访问就会出现越界的问题。而在Rust中,一旦越界的后果是极其严重的,可以导致Rust当前线程panic。因此,除非你确定自己在干什么或者在for循环中,不然我们不推荐通过下标访问。

以下是例子:

  1. let a = vec![1, 2, 3];
  2. assert_eq!(a[1usize], 2);

Rust中安全的下标访问机制:—— .get(n: usize).get_mut(n: usize)) 函数。函数返回一个Option<&T> (Option<&mut T>),当Option == None的时候,即下标越界,其他情况下,我们能安全的获得一个Vec里面元素的引用。

  1. let v =vec![1, 2, 3];
  2. assert_eq!(v.get(1), Some(&2));
  3. assert_eq!(v.get(3), None);

越界访问

如果你尝试访问并不存在的索引:

  1. let v = vec![1, 2, 3];
  2. println!("Item 7 is {}", v[7]);

那么当前的线程会panic并输出如下信息:

  1. thread '<main>' panicked at 'index out of bounds: the len is 3 but the index is 7'

如果你想处理越界错误而不是 panic,使用像getget_mut这样的方法,他们当给出一个无效的索引时返回None

  1. let v = vec![1, 2, 3];
  2. match v.get(7) {
  3. Some(x) => println!("Item 7 is {}", x),
  4. None => println!("Sorry, this Vector is too short.")
  5. }

迭代

对于可变数组,Rust提供简单的遍历形式—— for循环,可以获得一个数组的引用、可变引用、所有权。

  1. let mut v = vec![1, 2, 3];
  2. for i in &v { .. } // 获得引用
  3. for i in &mut v { .. } // 获得可变引用
  4. for i in v { .. } // 获得所有权,注意此时Vec的属主将会被转移!!

但是,这么写很容易出现多层for循环嵌套,Vec提供了一个into_iter()方法,能显式地将自己转换成一个迭代器。

Slice

Slice是一个引用视图。它有利于安全,有效的访问数组的一部分而不用进行拷贝,slice并不是直接创建的,而是引用一个已经存在的变量。有预定义的长度,是可变或不可变的。

可以用一个&[]的组合从多种数据类型创建一个slice。&类似于引用,带有一个范围的[],允许你定义slice的长度:

  1. let a = [0, 1, 2, 3, 4];
  2. let complete = &a[..]; // A slice containing all of the elements in a
  3. let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
  4. fn main() {
  5. /* Internally, it works as this:
  6. let _slice = [1, 2, 3, 4, 5];
  7. let slice = &_slice; */
  8. let slice = &[1, 2, 3, 4, 5];
  9. assert_eq!(slice[0], 1);
  10. let slice = &mut [1, 2, 3];
  11. // Write data into slice
  12. slice[1] = 99;
  13. assert_eq!(slice[1], 99);
  14. }

Slice可自动转化为迭代器,如果切片是由Array而來

  1. fn main() {
  2. let array = ["eins", "zwei", "drei", "vier", "fünf"];
  3. // It works when the array size <= 32
  4. for element in &array {
  5. println!("{}", element);
  6. }
  7. }
  8. //-----------------------------------
  9. extern crate rand;
  10. use rand::Rng;
  11. fn main() {
  12. const SIZE: usize = 10;
  13. let mut array = [0; SIZE];
  14. for element in &mut array {
  15. *element = rand::thread_rng().gen_range(1, 100 + 1);
  16. }
  17. }

案例选读: 插入排序法

  1. //调用rand库
  2. extern crate rand ;
  3. 使用 rand :: Rng ;
  4. fn main () {
  5. //初始化变量
  6. const SIZE usize = 10 ;
  7. mut数组: [ i32 ; SIZE ] = [ 0 ; SIZE ] ;
  8. //用随机整数设置数组元素
  9. 对于我在 0 ..SIZE {
  10. 阵列[我] =兰特:: thread_rng () .gen_range 1 100 + 1 );
  11. }
  12. //打印未排序的数组
  13. 打印!(“排序前:” );
  14. display_slice (& array );
  15. //插入排序。
  16. //就地修改数组。
  17. 对于我在 1 .. array.len ()) {
  18. x = array [ i ] ; //临时数据
  19. mut j = i ;
  20. j > 0 && array [ j - 1 ] > x {
  21. array [ j ] = array [ j - 1 ] ; //移动元素一步
  22. j - = 1 ;
  23. }
  24. 数组[ j ] = x ; //放回临时数据
  25. }
  26. //打印排序的数组
  27. 打印!(“排序后:” );
  28. display_slice (& array );
  29. }
  30. //用任意大小打印数组的功能
  31. fn display_slice slice &[ i32 ] {
  32. 对于我在 0 ..slice.len () {
  33. 打印!(“{}” slice [ i ] );
  34. 如果我< slice.len () - 1 {
  35. 打印!(“,” );
  36. }
  37. }
  38. println !(“” );
  39. }