rust之vector笔记

rust Apr 28, 2021

描述

vector就是rust里面的动态增加元素的列表类型。官网中的定义是一个在堆上分配内存,可以持续增长的array类型。写作Vec,也是声明的定义。Vectors有O(1)的索引时间复杂度,在尾部插入和弹出也是O(1)的时间复杂度。

声明定义

rust的声明定义如下,其实我也看不太懂,反正是一个struct。

pub struct Vec<T, A = Global> 
where
    A: Allocator, 
 { /* fields omitted */ }

属性

vector的属性iu两个,但是我们都没办法直接访问。

pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
    buf: RawVec<T, A>,
    len: usize,
}

len()

获取当前vector长度

capacity()

获取当前容量。

is_empty()

当前vector是否为空

初始化

初始化有两种方式

  1. 调用new方法
let mut vec = Vec::new();
vec.push(1);
vec.push(2);

  1. 使用宏
let vec = vec![1,2,3];
vec.push(4);
assert_eq!(vec, [1,2,3,4]);



还支持,初始化单一值的快捷方式

let vec = vec![0; 5]; // 初始化5个0
assert_eq!(vec, [0, 0, 0, 0, 0]);
  1. 只申请空间不初始化
    可以使用with_capacity函数来申请空间,我们可以看到vec的长度是0,空间是我们申请的大小。但是一般不这么做,官网说这样性能不好。
  let vec: Vec<i32> = Vec::with_capacity(10);
  assert_eq!(0, vec.len());
  assert_eq!(10, vec.capacity());

索引元素

vec支持类似数组的方式索引元素。因为他们都实现了index的trait。

let v = vec![0, 2, 4, 6];
println!("{}", v[1]); // it will display '2'

但是如果索引不存在的元素、越界的元素会导致panic。

let v = vec![0, 2, 4, 6];
println!("{}", v[6]); // it will panic!

安全的索引元素的方式是使用get、get_mut函数。
get函数返回的结果是一个Opiton的slice。参数是单个位置的索引或者多个位置索引的slice。


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

get_mut函数的参数和get函数一致,但是返回的结果是可以修改的引用。


    let mut x = vec![0, 1, 2];

    if let Some(elem) = x.get_mut(1) {
        *elem = 42;
    }
    assert_eq!(x, &[0, 42, 2]);

改变容积

reserve

保留容积到某个值。下面的例子是保留到10,所以vec要至少保留当前元素的容量+10。实际的容量一般是20,vector内部有一套申请容积的规则。

let mut vec = vec![1];
vec.reserve(10);
assert!(vec.capacity() >= 11);

reserve_exact

名字也可以看出来,作用是保留确切大小的容积。

shrink_to_fit

也是减少容积。[todo] 具体的作用和reserve的不同之处

添加元素

append

添加另一个vector的所有元素,并清空另一个vector。


let mut vec = vec![1, 2, 3];
let mut vec2 = vec![4, 5, 6];
vec.append(&mut vec2);
assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
assert_eq!(vec2, []);

插入元素

insert

在对应索引处,插入一个元素,将后面的元素右移


let mut vec = vec![1, 2, 3];
vec.insert(1, 4);
assert_eq!(vec, [1, 4, 2, 3]);
vec.insert(4, 5);
assert_eq!(vec, [1, 4, 2, 3, 5]);


push

在vector末尾插入一个元素

删除元素

pop

弹出vector最后一个元素。

clear

清空所有元素,但是不释放空间

let mut v = vec![1, 2, 3];

v.clear();

assert!(v.is_empty());
assert_eq!(v, []);

truncate

就是直接删除,包括空间。有以下几种情况

let mut vec = vec![1, 2, 3, 4, 5];
vec.truncate(2);  //就剩两元素
assert_eq!(vec, [1, 2]);  


let mut vec = vec![1, 2, 3];
vec.truncate(8); //没有删除任何元素
assert_eq!(vec, [1, 2, 3]);

let mut vec = vec![1, 2, 3];
vec.truncate(0); // 相当于clear函数
assert_eq!(vec, []); 


remove

删除元素,并返回。剩下的所有元素左移。

swap_remove

删除单个元素,返回删除元素,并将最后一个元素挪到删除元素位置。

swap

交换给定索引的元素


    let mut v = vec![1, 2, 3];
    v.swap(1,2);

    assert_eq!(vec![1,3,2], v);

遍历

iter

iter返回都是引用,这个函数返回的是不可变的引用。


    let  v = vec![1, 2, 3];
    for x in v.iter() {
        println!("{}", x);
    }

iter_mut

可变的iter


    let mut  v = vec![1, 2, 3];

    for x in v.iter_mut() {
        *x  += 1;
    }
    assert_eq!(vec![2,3,4], v);

查找

contains

判断元素是否在vector内,参数需要是一个引用类型


    let v = vec![10, 40, 30];
    assert!(v.contains(&30));
    assert!(!v.contains(&50));

start_with

从开始位置判断slice是否在vector内。


let v = vec![10, 40, 30];
assert!(v.starts_with(&[10]));
assert!(v.starts_with(&[10, 40]));
assert!(!v.starts_with(&[50]));
assert!(!v.starts_with(&[10, 50]));

end_with

从末尾判断slice是否在vector内


let v = vec![10, 40, 30];
assert!(v.ends_with(&[30]));
assert!(v.ends_with(&[40, 30]));
assert!(!v.ends_with(&[50]));
assert!(!v.ends_with(&[50, 30]));

binary_search

对一个排好序的vec,使用二分查找,返回查找元素的索引的slice。


let s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];

assert_eq!(s.binary_search(&13),  Ok(9));
assert_eq!(s.binary_search(&4),   Err(7));
assert_eq!(s.binary_search(&100), Err(13));
let r = s.binary_search(&1);
assert!(match r { Ok(1..=4) => true, _ => false, });

排序

sort

对vector进行排序,排序的结果是stable的(不会改变相同元素的位置)。算法复杂度是O(nlogn)。算法的实现是timsort的类似实现。

let mut v = vec![-5, 4, 1, -3, 2];

v.sort();
assert_eq!(v, [-5, -3, 1, 2, 4]);

sort_unstable

要比sort方法理论上快。

split

split_off

根据给的索引,将vec分裂成两个vectors

let mut vec = vec![1, 2, 3];
let vec2 = vec.split_off(1);
assert_eq!(vec, [1]);
assert_eq!(vec2, [2, 3]);

字符串操作

concat

拍平一个vector


assert_eq!(["hello", "world"].concat(), "helloworld");
assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);

join

将vector的所有元素进行拼接(拍平),可以添加分隔符号。


assert_eq!(["hello", "world"].join(" "), "hello world");
assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);

获取slice

从一个vector获取他的slice的方式有两种,一种是通过引用的方式,一种是通过函数。

    
    let mut v = vec![1, 2, 3];
    let v_slice = &v; // 常用 
    let v_slice_part = &v[1..2]; // 获取第二个和第三个元素的slice 
    let v_slice_all = &v[..]; // 不常用的
    let v_slice_all_1 = &v[0..];; // 也不是很常用



as_slice

let mut buffer = vec![0; 3];
let buffer = buffer.as_slice();

as_mut_slice

let mut buffer = vec![0; 3];
let buffer = buffer.as_mut_slice()

总结

把官方ref里面关于vector中常用的方法进行总结了下,文档看了好几遍,没有把lambda相关,以及night版本的函数加进来。