• Rust 从入门到精通12-集合


    Rust 标准库中还提供了一系列被称为 集合collections)的数据结构,类似于JDK中 java.util 包下面的一些集合类(List/Set/Map等),这类集合指向的数据是存储在堆上,意味着数据的数量不必在编译期就已知,并且还能随着程序的运行增大或缩小,每种集合都有其适用的场景,在我们日常开发过程中是非常有用的。

    1、Vector

    1.1 作用

    由标准库提供,用来存储多个相同类型的值,其值在内存中是连续存放的。

    相关 api 介绍:https://doc.rust-lang.org/std/vec/struct.Vec.html

    1.2 创建

    ①、Vec::new 函数

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

    因为没有向这个 vector 中插入任何值,Rust 并不知道我们想要储存什么类型的元素,所以无法进行类型推断,这里我们就增加了泛型 ,表示这个集合 v 只能存放 i32 类型的数据。

    ②、vec![] 宏

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

    这里我们提供了 i32 类型的初始值,Rust 可以推断出 v 的类型是 Vec,因此不需要加上泛型注解。

    1.3 添加
    fn main() {
        let mut v: Vec<i32> = Vec::new();
        v.push(1);
        v.push(2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    通过 push() 向集合末尾添加元素,注意要声明为 mut 使其可变。

    1.4 修改

    直接通过下标的方式修改:

    fn main() {
        let mut v: Vec<i32> = Vec::new();
        v.push(1);
        v.push(2);
        v[0] = 3;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.5 删除

    ①、通过下标删除

    fn main() {
        let mut v: Vec<i32> = Vec::new();
        v.push(1);
        v.push(2);
        v.remove(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ②、删除末尾元素

    v.pop();
    
    • 1
    1.6 遍历
    fn main() {
        let mut v: Vec<i32> = vec![1,2,3,4];
        // 遍历引用地址
        for x in &v{
            print!("{} ", x);
        }
    
        // 遍历下标
        for x in 0..v.len(){
            if let Some(num) = v.get(x) {
                print!("{} ", num);
            }
        }
    
        for x in v.iter() {
            print!("{} ", x);
        }
    
        for x in v.into_iter() {
            print!("{} ", x);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1.7 遍历修改
    fn main() {
        let mut v: Vec<i32> = vec![1,2,3,4];
        for x in &mut v {
            *x += 1;
        }
        println!("&mut v {:?}", v);
        for x in v.iter_mut() {
            *x += 1;
        }
        println!("v.iter_mut {:?}", v);
        for x in 0..v.len() {
            if let Some(num) = v.get_mut(x) {
                *num += 1;
            }
        }
        println!("0..v.len() get_mut {:?}", v);
        let v1: Vec<i32> = v.iter().map(|x| x + 1).collect();
        println!("v.iter().map().collect() {:?}", v1);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1.8 使用枚举存储不同类型

    前面我们说vector 只能储存相同类型的值,但实际会有很多情况下我们要存储不同类型的值,这时候就可以使用枚举。

    因为枚举成员都被定义为相同的枚举类型。

    fn main() {
        let row = vec![
            SpreadsheetCell::Int(3),
            SpreadsheetCell::Text(String::from("blue")),
            SpreadsheetCell::Float(10.12),
        ];
    }
    
    enum SpreadsheetCell {
        Int(i32),
        Float(f64),
        Text(String),
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2、HashMap

    2.1 作用

    基于 hash 算法的存储一组键值对 (key- value- pair) 的容器,可以通过 K(任意类型)来寻找数据,而不是通过索引。

    2.2 创建

    注意必须首先通过 use 引用标准库中集合部分的 HashMapHashMap 没有被 prelude 自动引用。

    标准库中对 HashMap 的支持也相对较少,例如,并没有内建的构建宏。

    use std::collections::HashMap;
    let mut map = HashMap::new();
    
    • 1
    • 2

    PS:注意上面不指明 map 的类型,编译是会报错的。要么指明编译类型 let mut map: HashMap = HashMap::new() ;要么通过类型推断,像 map 中添加数据。

    2.3 添加
    fn main() {
        let mut scores = HashMap::new();
        scores.insert(String::from("Blue"), 10);
        scores.insert(String::from("Yellow"), 50);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    像 vector 一样,哈希 map 将它们的数据储存在堆上,这个 HashMap 的键类型是 String 而值类型是 i32

    类似于 vector,哈希 map 是同质的:所有的键必须是相同类型,值也必须都是相同类型。

    2.4 修改

    ①、覆盖一个值

    用相同的键插入一个不同的值,也就是连续调用两次 insert ,其 key 相同,value 不同。

    fn main() {
        let mut scores = HashMap::new();
        scores.insert(String::from("Blue"), 10);
        scores.insert(String::from("Blue"), 50);
        println!("{:?}", scores);//{"Blue": 50}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ②、key 不存在则插入,存在就不做操作

    fn main() {
        let mut scores = HashMap::new();
        scores.insert(String::from("Blue"), 10);
        scores.entry(String::from("Yellow")).or_insert(50);
        scores.entry(String::from("Blue")).or_insert(50);
        println!("{:?}", scores);//{"Blue": 10, "Yellow": 50}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Entryor_insert 方法在键对应的值存在时就返回这个值的可变引用,如果不存在则将参数作为新值插入并返回新值的可变引用。

    ③、key 不存在则插入,存在做更新操作

    fn main() {
        use std::collections::HashMap;
        let text = "hello world wonderful world";
        let mut map = HashMap::new();
        for word in text.split_whitespace() {
            let count = map.entry(word).or_insert(0);
            *count += 1;
        }
    
        println!("{:?}", map);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    打印结果:

    {“world”: 2, “hello”: 1, “wonderful”: 1}

    由于Entryor_insert 方法在键对应的值存在时会返回这个值的可变引用,我们通过 * 解引用然后去修改里面的值。

    2.5 删除
    fn main() {
        let mut scores = HashMap::new();
        scores.insert(String::from("Blue"), 10);
        scores.insert(String::from("Yellow"),50);
        scores.remove(&String::from("Yellow"));
        println!("{:?}", scores);//{"Blue": 10}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.6 遍历
    fn main() {
        let mut scores = HashMap::new();
        scores.insert(String::from("Blue"), 10);
        scores.insert(String::from("Yellow"),50);
        println!("{:?}", scores);//{"Blue": 10}
        for (key, value) in &scores {
            println!("{}: {}", key, value);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    Vue:vue-cli中render函数的作用
    技术分享 | 客户说 insert 慢,我该怎么办
    Linux线程安全
    通过matlab实现水产养殖鱼类成熟度自动分析系统
    Linux搭建GitLab私有仓库,并内网穿透实现公网访问
    cmake是什么,为什么现在都用cmake,cmake编译原理和跨平台示例
    E. Sending a Sequence Over the Network(DP)
    不要用jOOQ串联字符串
    Kubernetes 节点异常检测
    信贷风控拒绝客户的捞回策略详解
  • 原文地址:https://blog.csdn.net/ysvae/article/details/126777626