Array-Vec-Slice
Array是一种线性的容器,储存同一种类型的数据,而其长度在生成后即固定下来,在内存中是连续而紧密排列的,好处在于可快速存取数据,Array是透过索引值存取数据,但当要改变长度时,效率则较差,因为要复制Array中的数据
//创建let mut array: [i32; 3] = [0; 3]; // 方式一let arr = [8,9,10]; // 方式二//修改array[1] = 1;array[2] = 2;for x in &array {print!("{} ", x);}
Rust的数组中的N(大小)也是类型的一部分,即[u8; 3] != [u8; 4]。
extern crate rand;use rand::Rng;fn main() {const SIZE: usize = 10;let mut array = [0; SIZE];for i in 0..array.len() {// Set a random number between 1 and 100array[i] = rand::thread_rng().gen_range(1, 100 + 1);}}
或是使用迭代器,
fn main() {let array = ["eins", "zwei", "drei", "vier", "fünf"];for element in array.iter() {println!("{}", element);}}//-----------------------------extern crate rand;use rand::Rng;fn main() {const SIZE: usize = 100;let mut array = [0; SIZE];for e in array.iter_mut() {*e = rand::thread_rng().gen_range(1, 100 + 1);}}
目前 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将其包裹,当成一个指针。
let v1: Vec<i32> = Vec::new(); // 方式一let v = vec![1, 2, 3, 4, 5]; // 方式二let v2 = vec![0;10]; //声明一个初始长度为10的值全为0的动态数组
从迭代器生成
因为Vec实现了FromIterator这个trait,因此,借助collect,我们能将任意一个迭代器转换为Vec。
let v: Vec<_> = (1..5).collect();let mut v2 = (0i32..5).collect::<Vec<i32>>();
使用枚举来储存多种类型
enum SpreadsheetCell {Int(i32),Float(f64),Text(String),}let row = vec![SpreadsheetCell::Int(3),SpreadsheetCell::Text(String::from("blue")),SpreadsheetCell::Float(10.12),];
访问元素
为了Vec特定索引的值,我们使用[],索引从0开始.
let v = vec![1, 2, 3, 4, 5];let r0 = v[1];let r1 = &v[2]; //当引用一个不存在的元素时,会造成panic!.let r2 = v.get(3); //当引用一个不存在的元素时,返回None.println!("The third element of v is{}, {},{}", r0, r1,r2);fn main() {let vec = vec![1, 2, 3];for i in 0..(vec.len()) {println!("{}", i);}}//--------------------------fn main() {let vec = vec![1, 2, 3];for element in vec.iter() {println!("{}", element);}}//----------------------------fn main() {let mut vec = vec![1, 2, 3];for i in 0..vec.len() {vec[i] = vec[i] * vec[i];}assert_eq!(vec[0], 1);assert_eq!(vec[1], 4);assert_eq!(vec[2], 9);}//----------------------------fn main() {let mut vec = vec![1, 2, 3];for element in vec.iter_mut() {*element = (*element) * (*element);}assert_eq!(vec[0], 1);assert_eq!(vec[1], 4);assert_eq!(vec[2], 9);}
另外值得注意的是你必须用usize类型的值来索引:
let v = vec![1, 2, 3, 4, 5];let i: usize = 0;let j: i32 = 0;// worksv[i];// doesn’tv[j];
用非usize类型索引的话会给出类似如下的错误:
error: the trait `core::ops::Index<i32>` is not implemented for the type`collections::Vec::Vec<_>` [E0277]v[j];^~~~note: the type `collections::Vec::Vec<_>` cannot be indexed by `i32`error: aborting due to previous error
随机访问
就像数组一样,因为Vec借助Index和IndexMut提供了随机访问的能力,我们通过[index]来对其进行访问,当然,既然存在随机访问就会出现越界的问题。而在Rust中,一旦越界的后果是极其严重的,可以导致Rust当前线程panic。因此,除非你确定自己在干什么或者在for循环中,不然我们不推荐通过下标访问。
以下是例子:
let a = vec![1, 2, 3];assert_eq!(a[1usize], 2);
Rust中安全的下标访问机制:—— .get(n: usize) (.get_mut(n: usize)) 函数。函数返回一个Option<&T> (Option<&mut T>),当Option == None的时候,即下标越界,其他情况下,我们能安全的获得一个Vec里面元素的引用。
let v =vec![1, 2, 3];assert_eq!(v.get(1), Some(&2));assert_eq!(v.get(3), None);
越界访问
如果你尝试访问并不存在的索引:
let v = vec![1, 2, 3];println!("Item 7 is {}", v[7]);
那么当前的线程会panic并输出如下信息:
thread '<main>' panicked at 'index out of bounds: the len is 3 but the index is 7'
如果你想处理越界错误而不是 panic,使用像get或get_mut这样的方法,他们当给出一个无效的索引时返回None:
let v = vec![1, 2, 3];match v.get(7) {Some(x) => println!("Item 7 is {}", x),None => println!("Sorry, this Vector is too short.")}
迭代
对于可变数组,Rust提供简单的遍历形式—— for循环,可以获得一个数组的引用、可变引用、所有权。
let mut v = vec![1, 2, 3];for i in &v { .. } // 获得引用for i in &mut v { .. } // 获得可变引用for i in v { .. } // 获得所有权,注意此时Vec的属主将会被转移!!
但是,这么写很容易出现多层for循环嵌套,Vec提供了一个into_iter()方法,能显式地将自己转换成一个迭代器。
Slice
Slice是一个引用视图。它有利于安全,有效的访问数组的一部分而不用进行拷贝,slice并不是直接创建的,而是引用一个已经存在的变量。有预定义的长度,是可变或不可变的。
可以用一个&和[]的组合从多种数据类型创建一个slice。&类似于引用,带有一个范围的[],允许你定义slice的长度:
let a = [0, 1, 2, 3, 4];let complete = &a[..]; // A slice containing all of the elements in alet middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3fn main() {/* Internally, it works as this:let _slice = [1, 2, 3, 4, 5];let slice = &_slice; */let slice = &[1, 2, 3, 4, 5];assert_eq!(slice[0], 1);let slice = &mut [1, 2, 3];// Write data into sliceslice[1] = 99;assert_eq!(slice[1], 99);}
Slice可自动转化为迭代器,如果切片是由Array而來
fn main() {let array = ["eins", "zwei", "drei", "vier", "fünf"];// It works when the array size <= 32for element in &array {println!("{}", element);}}//-----------------------------------extern crate rand;use rand::Rng;fn main() {const SIZE: usize = 10;let mut array = [0; SIZE];for element in &mut array {*element = rand::thread_rng().gen_range(1, 100 + 1);}}
案例选读: 插入排序法
//调用rand库extern crate rand ;使用 rand :: Rng ;fn main () {//初始化变量const SIZE : usize = 10 ;让 mut数组: [ i32 ; SIZE ] = [ 0 ; SIZE ] ;//用随机整数设置数组元素对于我在 0 ..SIZE {阵列[我] =兰特:: thread_rng () .gen_range (1 , 100 + 1 );}//打印未排序的数组打印!(“排序前:” );display_slice (& array );//插入排序。//就地修改数组。对于我在 1 .. ( array.len ()) {让 x = array [ i ] ; //临时数据让 mut j = i ;而 j > 0 && array [ j - 1 ] > x {array [ j ] = array [ j - 1 ] ; //移动元素一步j - = 1 ;}数组[ j ] = x ; //放回临时数据}//打印排序的数组打印!(“排序后:” );display_slice (& array );}//用任意大小打印数组的功能fn display_slice ( slice : &[ i32 ] ) {对于我在 0 ..slice.len () {打印!(“{}” , slice [ i ] );如果我< slice.len () - 1 {打印!(“,” );}}println !(“” );}
