Rust与Vector

357 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

Rust与Vector

Rust标准库中内置了许多集合,这与tuple有区别,集合是被存放在heap堆内存上,并且不需要声明时就指定长度,这也使其更加灵活。

我们常用的集合为:Vector,String,HashMap,本篇文章将介绍Vector这一数据类型

Vector

使用Vector存储多个值

Vector类型为Vec<T>,其中关于Vector我们需要知道的是:

  • 它由标准库提供
  • 可以存储多个值
  • 只能存储相同类型的数据
  • 值在内存中是连续存放的

创建Vector

我们可以使用Vec::new()来创建一个Vector:

fn main() {
    let v: Vec<i32> = Vec::new();
}

一般我们不需要显示的指明vector的类型,当我们存入一个数据时,编译器会将这个值的类型作为vector的类型。

通常我们使用vec!宏来通过初始值来创建一个Vec<T>

let v = vec![1, 2, 3];//v: Vec<i32>

更新Vector

我们使用push向vector添加元素

我们先声明一个vector,但不声明类型,这时候会报错:

let mut v = Vec::new();//v:Vec<{unknown}, Global>

我们在后面使用push来添加元素,这时报错就消失了,并且我们会得到vector的类型:

let mut v = Vec::new();//v:Vec<i32, Global>
v.push(1);
v.push(2);
v.push(3);
v.push(4);

我们使用mut声明是因为我们会修改vector,向里面添加元素。

注意vector的类型是一致的:

let mut v = Vec::new();
v.push(1);
v.push(false);//error:mismatched types

删除Vector

与struct一样:

  • 当vector离开作用域的时候,它会被清理掉
  • 它所有的元素也会被清理掉

但是当vector中的元素被引用的时候,这里的情况就变复杂了,下面将对这种情况进行研究

读取vector的值

有两种方式可以读取vector的值:

  • 使用索引
  • 使用get方法
fn main() {
    let v = vec![1, 2, 3, 4];
    let third = &v[2];
    //the third value of v is 3
    println!("the third value of v is {}", third);

    match v.get(2) {
        // the third value of v is 3
        Some(third) => println!("the third value of v is {}", third),
        None => println!("there is no third element"),
    }
}

使用索引和get处理访问越界的区别

  • 索引:panic
  • get:返回None

我们尝试将索引的值改为100,很明显,这个值超出了vector的范围:

let v = vec![1, 2, 3, 4];
let third = &v[100];//会引起panic
println!("the third value of v is {}", third);

而使用get方法不会:

fn main() {
    let v = vec![1, 2, 3, 4];

    match v.get(100) {
        Some(third) => println!("the third value of v is {}", third),
        None => println!("there is no third element"),
    }
    //there is no third element
}

这是因为,匹配的值的类型为一个Option<T>,超出索引时,这个表达式的值为None

所有权和借用规则

不能在同一作用域内同时拥有可变和不可变引用:

let mut v = vec![1, 2, 3, 4];
let third = &v[2];
v.push(5); //cannot borrow `v` as mutable because it is also borrowed as immutable
println!("The Third v is {}", third);

报错的原因:vector在内存中的摆放是连续的,如果我们push,就可能没有这么大的内存块了。内存可能就会进行重新分配,然后就会从新找一块内存并且将值push到vector中,而原来的内存就可能被释放或者重新分配,这时候,我们的third就变成一个悬空指针了,所以会报错。

遍历Vector中的值

使用for循环遍历:

let v = vec![1, 2, 3];
for i in &v {
    println!("{}", i);
}
//输出
//1
//2
//3

我们也可以修改vector中的值:

let mut v = vec![1, 2, 3];
for i in &mut v {
    *i += 100;
}

for i in v {
    println!("{}", i);
}
// 101
// 102
// 103

Vector+Enum的例子

我们知道vector中只能存放同种数据,那遇到存放不同类型的需求该怎么办呢?

我们在前面学到,enum的变体能够存储不同类型,并且能够附加数据。最重要的是,变体都在同一个enum下,也就是说它们的类型是一致的。

enum SpreadSheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}

let v = vec![
    SpreadSheetCell::Int(22),
    SpreadSheetCell::Float(2.2),
    SpreadSheetCell::Text(String::from("nice demo")),
]; //v: Vec<SpreadSheetCell>

为什么rust需要在编译时就知道vector的值呢?因为vector是存放在heap上,这样可以提前知道需要多少内存。如果类型不同,就有可能遇到某些元素有某个方法,而某些没有。而通过Vector+Enum的组合,rust能够在编译时就知道所有情况。运行时就可以处理了。