Rust 动态数组

动态数组:Vec< T >,T表示泛型。

创建动态数组

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

创建动态数组的声明需要声明类型,因为数组中没有数据,rust无法推导。如果你放入了数据,rust一般能推导出正确的数据类型。

rust提供了vec!宏,可以根据我们的值来创建一个新的动态数组。

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

在动态数组中加入数据

使用push在数组的最后加入数据,注意修改数组要加mut,因为你push了i32的数据,所以rust推导出了vec的类型。

fn main() {
    let mut v = Vec::new();

    v.push(5);
    v.push(6);
    v.push(7);
    v.push(8);
}

销毁动态数组也会销毁其中的元素

和struct一样,如果动态数组离开作用域,那么动态数组也会被销毁

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

        // do stuff with v
    } // <- v goes out of scope and is freed here
}

但如果有引用指向了动态数组中的数据,情况会变得复杂。

读取动态数组中的元素

有两种方法:

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

    let third: &i32 = &v[2];
    println!("The third element is {}", third);

    match v.get(2) {
        Some(third) => println!("The third element is {}", third),
        None => println!("There is no third element."),
    }
}

可以看到第一种是使用了索引,第二种使用了get方法。 第一种方法是一个引用,第二种方法返回的是一个option。 当数组越界时,这两种方法的不同之处就体现出来了。 当使用引用越界时,程序会直接崩溃,如果你希望程序崩溃,索引是可用的。 当使用get越界时,程序只是返回了一个none,程序能继续运行。 可以视情况使用。

在存在指向动态数组元素的引用时尝试向动态数组中添加元素

最恶心的不是这个,而是关于可变引用的所有权规则。 之前我们说过,在同一作用域中如果存在一个可变引用,就不能使用其他任何引用。 接下来看这个错误代码:

//错误代码
fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let first = &v[0];

    v.push(6);

    println!("The first element is: {}", first);
}

这个例子首先声明了一个可变的动态数组,然后使用了一个不可变引用,最后向数组中push了一个数据。

我们先来了解一下vec的原理,其实和c++的stl中的vector原理时一样的,我就从以前博客复制下来这一段:

值得注意的一点,当插入时容量不够:

  1. 会先开辟新的内存空间,新空间大小为 old_size + max(old_size, n)。
  2. 然后再将旧数据和新数据放入新空间中。
  3. 释放旧空间。

意思就是说,vec的地址空间可能会因为push变动。

至于上面代码为什么错误,官方的解释时,因为vec的地址空间可能因为push变动,所以不可变引用将会时危险的。

但我的理解却和官方有点不一样,看到这篇博客的就当笑话看看:因为v.push是一个方法,所以有&self参数,因为会修改v的数据,所以应该是&mut self,是一个可变引用,如果之前使用了不可变引用就会违背关于可变引用的所有权规则。所以会报错。

遍历动态数组中的值

一种是直接用索引遍历,缺点是可能发生数组越界:

fn main(){
    let v=vec![1,2,3,4,5,6];
    for i in 0..5{
        println!("{}",v[i]);
    }
}

第二种是通过不可变引用:

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
        println!("{}", i);
    }
}

第三种是通过可变引用,还可以修改其值:

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
}

使用枚举类型来存储多个类型的值

动态数组只能存储相同类型的值,有些情况下我们需要在数组中存不同类型的值,我们可以通过枚举类型来实现:使用动态数组存储枚举类型。

fn main() {
    enum SpreadsheetCell {
        Int(i32),
        Float(f64),
        Text(String),
    }

    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Float(10.12),
    ];
}

但是有些情况下,你无法枚举你所需要的所有类型,那么我们会在之后讨论动态trait。

下一章:Rust 所有权

rust通过所有权系统管理内存,该系统具有一组在编译时检查的规则。程序运行时,所有所有权功能都不会减慢其运行速度。 所有权规则 首先,让我们看一下所有权规则。在通过示例进行说明时,请牢记以下规则: Rust中的每个值都有一 ...