Skip to main content

Vector

使用 Vector 存储多个值

  • Vec<T>,叫做 Vector
    • 由标准库提供
    • 可以储存多个值
    • 只能存储相同类型的数据
    • 值在内存中连续存放

创建 Vector

  • Vec::new 函数
tip
fn main() {
let v: Vec<i32> = Vec::new();
}
  • 使用初始值创建 Vec<T> ,使用 vec! 宏

vec!:它会指定你使用的初始值来创建一个 Vector

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

更新 Vector

  • push
fn main() {
let mut v: Vec<i32> = Vec::new();

v.push(1);

println!("{:?}", v);
}

删除 Vector

  • 与任何其它 struct 一样,当 Vector 离开作用域后
    • 会被清理掉
    • 所有的元素也会被清理掉

读取 Vector 的元素

  • 两种方式可以引用 Vector 里的值:

    • 索引
      fn main() {
    let v = vec![1, 2, 3, 4, 5];
    let two: &i32 = &v[1];
    println!("The tow element is {}", two);
    }
    • get 方法
      fn main() {
    let v = vec![1, 2, 3, 4, 5];

    match v.get(1) {
    Some(two) => println!("the two element is{}", two),
    None => println!("There is no two element"),
    }
    }
  • 索引 VS get 处理访问越界

    • 索引:索引一旦溢出就会引起程序恐慌 panic
    • 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); // 又变成不可变引用
}
Vector 的工作原理
  • 我们引用的是 Vector 的第一个元素,那么我们为啥还要关心向 Vector 的末尾添加一个元素这样的状况呢?。

  • Vector 里面的元素在内存中的摆放是连续内存,一个挨着一个放置的,所以再往 Vector 里面添加一个元素的时候在内存中就可能没有这么大的连续内存块了,它就可能把这个内存重新分配了一下,再找 一个足够大的的内存来放置这个添加了元素之后的 Vector ,如果这样,原来的那块内存就可能被释放,或者是重新分配。

  • 在内存释放或者是重新分配之后,我们的 first 变量如果规则允许,它仍然会指向原来的那块内存地址,这样程序就会出问题了,所以 借用规则 就会防止类似这样的事情发生。

fn main() {
let mut v = vec![50, 20, 84];

for i in &mut v {
*i += 50;
println!("{}", i);
}
}

enum 来存储多种数据类型

  • Enum 的变体可以附加不同类型的数据
  • Enum 的变体定义在同一个 enum 类型下

#[derive(Debug)]
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}

fn main() {
let low = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Float(13.14),
SpreadsheetCell::Text(String::from("Hello World"))
];

println!("{:?}", low);
}

  • 通过这个例子我们可以看到,通过使用可附加数据的枚举类型我们就可以在 Vector 里面存放不同类型的数据,那么 Rust 为什么在编译的时候就需要知道 Vector 里面元素的类型呢?
    • 因为这样它就可以知道在 Heap 上到底需要多少内存了
    • 而且同时也明确了到底哪些类型的数据可以存放在 Vector 里面
    • 假如这个 Vector 什么类型的数据都允许存放在里面,那么当对 Vector 的元素进行操作的时候由于它们类型的不同有可能这些操作在某种类型上就是合法的,而在另外一些类型上就是不合法的, 这个时候程序有可能就会出错。
    • 使用 SpreadsheetCell 这种枚举配合 Match 表达式这种方式,Rust 就可以在编译时提前知晓所有的可能情况,在运行的时候就可以正确的处理。
    • 虽然在 上面的代码中 Vector 可以存放多种数据类型,但是有条件的,就是我们必须提前知道到底有哪些数据类型,我们得知道数据详尽的类型,否则的话,如果是这个类型有无限种可能,或者叫 不详尽,那么使用枚举也没有办法,因为这个 SpreadsheetCell 枚举没法定义,针对这种情况,我们可以使用 Trait 对象。