Rust学习总结之vector

        用过C++的相信对vector概念不陌生了,C++中我们称vector为容器,它能够像容器一样存放各种类型的对象。Rust中同样也有vector概念,在Rust中vector 允许我们在一个单独的数据结构中储存多个值,所有值在内存中彼此相邻排列,在内存中的存储形式和数组一样,vector 只能储存相同类型的值。但是借助另一种结构(枚举),我们可以用vector存储不同类型的值,当然这是包了一层,下面我们讲一下Rust的vector详细用法。

一:vector的实例创建

fn main() {
    let vec_ins:Vec<u32> = Vec::new();
}

        上面我们通过Vec的new函数创建了一个vector实例,并指定了其里面存储的值是u32类型,那我们用new创建的时候能不能不指定值类型呢。

        这是不允许的,如果用new创建的时候不指定类型,那么因为没有向这个 vector 中插入任何值,Rust 并不知道我们想要储存什么类型的元素。这一点非常重要。vector 是用泛型实现的,第 10 章会涉及到如何对你自己的类型使用它们。现在,我们知道 Vec 是一个由标准库提供的类型,它可以存放任何类型,而当 Vec 存放某个特定类型时,那个类型位于尖括号中。        

         那假如我在创建的同时,传入vector的元素,是不是就意味着不用显示的指定类型。

fn main() {
    let vec_ins = vec![1, 2, 3];
    println!("vec is {:?}",vec_ins); 
}

运行结果:

PS F:\skillup\rust\hello_world\greeting> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target\debug\greeting.exe`
vec is [1, 2, 3]

vector创建的同时传入了元素,Rust 就可以根据插入的元素推断出存放的类型。更常见的做法是使用初始值来创建一个 Vec,而且为了方便 Rust 提供了 vec! 宏。这个宏会根据我们提供的值来创建一个新的 Vec。

二:vector的元素插入

我们创建了vector,那么如何向vector中插入元素。

fn main() {
    let mut vec_ins:Vec<char> = Vec::new();
    vec_ins.push('f');
    vec_ins.push('t');
    vec_ins.push('z');
    println!("vec is {:?}",vec_ins); 
}

运行结果:

PS F:\skillup\rust\hello_world\greeting> cargo run
   Compiling greeting v0.1.0 (F:\skillup\rust\hello_world\greeting)
    Finished dev [unoptimized + debuginfo] target(s) in 1.19s
     Running `target\debug\greeting.exe`
vec is ['f', 't', 'z']

Rust中可以使用 push 方法往vector中插入元素

三:vector的元素读取

在Rust中我们有两种方法来获取vector中元素的值,一是通过索引,二是通过get方法。下面我们来看一个具体的例子

fn main() {
    let mut vec_ins:Vec<char> = Vec::new();
    vec_ins.push('f');
    vec_ins.push('t');
    vec_ins.push('z');
    println!("vec is {:?}",vec_ins); 

    let second_ele= vec_ins[1];
    println!("the second element is {}",second_ele); 

    match vec_ins.get(1) {
        Some(second_ele) => println!("The second element is {}", second_ele),
        None => println!("There is no second element."),
    }
}

运行结果:

S F:\skillup\rust\hello_world\greeting> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target\debug\greeting.exe`
vec is ['f', 't', 'z']
the second element is t
The second element is t

        Rust 有两个引用元素的方法的原因是程序可以选择如何处理当索引值在 vector 中没有对应值的情况。

        当引用一个不存在的元素时 Rust 会造成 panic。这个方法更适合当程序认为尝试访问超过 vector 结尾的元素是一个严重错误的情况,这时应该使程序崩溃。比如vector总共有5个元素,你用下标去获取第6个元素,就是越界访问,这时候程序就panic了,当 get 方法被传递了一个数组外的索引时,它不会 panic 而是返回 None。当偶尔出现超过 vector 范围的访问属于正常情况的时候可以考虑使用它。接着你的代码可以有处理 Some(&element) 或 None 的逻辑。例如,索引可能来源于用户输入的数字。如果它们不慎输入了一个过大的数字那么程序就会得到 None 值,你可以告诉用户当前 vector 元素的数量并再请求它们输入一个有效的值。这就比因为输入错误而使程序崩溃要友好的多!

        一旦程序获取了一个有效的引用,借用检查器将会执行所有权和借用规则来确保 vector 内容的这个引用和任何其他引用保持有效。不能在相同作用域中同时存在可变和不可变引用的规则。当我们获取了 vector 的第一个元素的不可变引用并尝试在 vector 末尾增加一个元素的时候,这是行不通的:

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的元素遍历

 我们可以用for循环来遍历vector元素

fn main() {
    let mut vec_ins:Vec<char> = Vec::new();
    vec_ins.push('f');
    vec_ins.push('t');
    vec_ins.push('z');
    println!("vec is {:?}",vec_ins); 

    for i in &vec_ins{
        println!("the element is {}",i);
    }
}

运行结果:

vec is ['f', 't', 'z']
the element is f
the element is t
the element is z

那么我们能不能遍历的同时改变vector元素的值呢

fn main() {
    let mut vec_ins:Vec<char> = Vec::new();
    vec_ins.push('f');
    vec_ins.push('t');
    vec_ins.push('z');
    println!("vec is {:?}",vec_ins); 

    for i in &mut vec_ins{
        *i = 'x'
    }
    println!("the element is {:?}",vec_ins);
}

运行结果:

vec is ['f', 't', 'z']
the element is ['x', 'x', 'x']

为了修改可变引用所指向的值,在使用 = 运算符之前必须使用解引用运算符(*)获取 i 中的值

五:vector借助枚举来存储不同类型的值

        上面讲到vector 只能储存相同类型的值。如果有这个限制vector说实话和数组功能就相差无几了。何谓道高一尺,魔高一丈,很幸运的是vector绝对有能力做到存储不同类型的值,不过要借助另外一个结构,枚举的成员都被定义为相同的枚举类型,所以当需要在 vector 中储存不同类型值时,我们可以定义并使用一个枚举!

#[derive(Debug)]
enum Student {
    Age(i32),
    Sex(char),
    Name(String),
}
fn main() {
    let student = vec![
        Student::Age(18),
        Student::Sex('男'),
        Student::Name(String::from("ftz"))
    ];
    println!("The student is {:?}",student);
}

   上面我们借助枚举来存储一个学生的信息,包括年龄,性别,名字,对应三种不同的数据类型。

六:vector学习总结

        Rust 在编译时就必须准确的知道 vector 中类型的原因在于它需要知道储存每个元素到底需要多少内存。第二个好处是可以准确的知道这个 vector 中允许什么类型。如果 Rust 允许 vector 存放任意类型,那么当对 vector 元素执行操作时一个或多个类型的值就有可能会造成错误。使用枚举外加 match 意味着 Rust 能在编译时就保证总是会处理所有可能的情况。

猜你喜欢

转载自blog.csdn.net/qq_27071221/article/details/129636654