概述

集合都是存储在 heap 中

1. Vector

  • 类型为 Vec<T>
  • 由标准库 std 提供
  • 可存储多个数据类型相同的值
  • 值在内存中连续存放

创建 Vector

  • 使用 Vec::new 可创建一个空的 vector
  • 使用 vec!创建带初值的 vector

    fn main() {
      let vec: Vec<i32> = Vec::new();
    
      let vec1 = vec![1, 2, 3];
    }
    

更新 Vector

  • push 添加成员

    fn main() {
      let mut vec: Vec<i32> = Vec::new();
    
      vec.push(1);
    }
  • pop 移除最后一个成员并返回

    #[derive(Debug)]
    enum Type {
      Int(u32),
      Float(f64),
      Text(String)
    }
    
    fn main() {
      let mut vec = vec![
          Type::Int(12),
          Type::Float(12.2),
          Type::Text(String::from("haha"))
      ];
    
      println!("{:?}", vec.pop()); //Some(Text("haha"))
      println!("{:?}", vec); // [Int(12), Float(12.2)]
    }

访问 Vector

  • 下标索引

    • 比较灵活,但访问越界时会导致程序 panic
  • get方法

    • 返回一个 options 枚举,能进行越界的异常处理,相对繁琐但更安全
    fn main() {
      let vec = vec![1, 2, 3];
    
      let two = vec[1];
    
      let getTwo = match vec.get(1) {
          Some(value) => {
              println!("value is {}", value);
              Some(value)
          },
          None => {
              println!("None");
              None
          }
      };
    
      println!("{}", two); // 2
      println!("{:?}", getTwo); // Some(2)
    }
    

遍历 Vector

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

    vec.push(4);

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

    println!("{:?}", vec) //[51, 52, 53, 54]
}

利用 enum 枚举来实现存放不同的数据类型

enum Type {
    Int(u32),
    Float(f64),
    Text(String)
}

fn main() {
    let vec = vec![
        Type::Int(12),
        Type::Float(12.2),
        Type::Text(String::from("haha"))
    ];
}

2. String

  • Rust 中字符串是 byte 的集合,其提供了一些方法,能将 byte 解析为文本
  • Rust 的核心语言层面只提供了一种字符串类型:字符串切片 &str

    • 字符串切片是对存储在其他地方 UTF-8 编码的字符串的引用,比如存储在二进制文件中的字符串字面值
  • String 类型

    • 是标准库所提供的,而不是语言层面提供
    • 可增长,可修改,可获得所有权
  • Rust 中的字符串只的是 String&str 这两种,标准库中还提供了其他的字符串类型:OsString,OsStr,CString,CStr

创建 String

fn main () {
    // 创建空字符串
    let str1 = String::new();
    // 将字符串切片转为 String
    let str2 = "hello,string".to_string();
    let str3 = String::from("haha");
}

更新 String

  • push_str
  • push
  • +
  • format!

    fn main () {
      let str1 = String::new();
      let str2 = "hello,string".to_string();
      let str3 = String::from("haha");
    
      // 更新 String
      let mut str4 = String::from("base, ");
    
      // 1.拼接字符串切片
      str4.push_str(&str3);
    
      println!("{}", str4); // base, haha
    
      // 2.拼接单个字符
      str4.push('!');
    
      println!("{}", str4); // base, haha!
    
      // 3.使用 + 拼接,这种方式会使得 str4 的所有权发生移动,后续就不能使用了
      let str5 = str4 + &str2;
    
      println!("{}", str5); // base, haha!hello,string
    
      // 4.format!进行拼接,这个宏不会获得参数的所有权
      let one = String::from("one");
      let two = String::from("two");
      let three = String::from("three");
    
      let merge_str = format!("{}-{}-{}", one, two, three);
    
      println!("{}", merge_str); // one-two-three
    }
    

访问 String

  • 不支持使用 索引 的形式访问

    • 因为一个字符可能不止占用一个字节,按照字节进行索引很可能无法获取到我们期望的值,所以 Rust 直接禁止了这种方式
  • String 是对 Vec<u8> 的包装
  • len 方法获取 String 的字节数,注意不是字符数
  • 字符串的单位有以下三个概念

    • 字节
    • 标量值
    • 字形簇 - 标准库没有提供获取这种形式的方法
    fn main () {
      let target = String::from("target");
    
      // 返回 字节 的迭代器
      for item in target.bytes() {
          /*
              byte item of target: 116
              byte item of target: 97
              byte item of target: 114
              byte item of target: 103
              byte item of target: 101
              byte item of target: 116
           */
          println!("byte item of target: {}", item)
      }
    
      // 返回 标量值 的迭代器
      for item in target.chars() {
          /*
              char item of target: t
              char item of target: a
              char item of target: r
              char item of target: g
              char item of target: e
              char item of target: t
          */
          println!("char item of target: {}", item)
      }
    }
    

切割 String

  • 可以使用 [] 配合 range 来创建字符串切片

    • 但需要谨慎使用,如果切割时跨越了字符边界,程序就会 panic,例如目标字符串 target 的第二字符占2个字节,这时如果对其第 0, 1 (target[0..2]) 字节位进行切片,则会导致 panic
    fn main () {
      let source_str = String::from("i am source string");
    
      let splice_str = &source_str[0..4];
    
      println!("{}", splice_str); // i am
    }
    

3. HashMap<k, v>

  • 键值对的形式存储数据
  • HashMap 没有在 prelude 中,需要使用 use str::collections::HashMap 引入

创建 HashMap

  • HashMap::new
  • collect

    use std::collections::HashMap;
    
    fn main() {
      let mut map = HashMap::new();
    
      map.insert("name", 10);
    
      println!("{:?}", map); // {"name": 10}
    
      // collect 创建 hashmap
      let keys = vec!["age", "size"];
      let values = vec![24, 12];
    
      let new_map: HashMap<_, _> = keys.iter().zip(values.iter()).collect();
    
      println!("{:?}", new_map); // {"age": 24, "size": 12}
    }

获取 HashMap 成员

  • hashMap[key]
  • hashMap.get(key)

    use std::collections::HashMap;
    
    fn main() {
      let keys = vec!["age", "size"];
      let values = vec![24, 12];
    
      let new_map: HashMap<_, _> = keys.iter().zip(values.iter()).collect();
    
      println!("{:?}", new_map); // {"age": 24, "size": 12}
    
      println!("{}", new_map[&"size"]); // 12
    
      match new_map.get(&"age") {
          Some(v) => println!("{}", v), // 24
          None => println!("None")
      }
    }
    

遍历 HashMap

use std::collections::HashMap;

fn main() {
    let mut config = HashMap::new();

    config.insert("a", "A");
    config.insert("b", "B");
    config.insert("c", "C");
    config.insert("d", "D");

    for (k, v) in &config {
        println!("{}, {}", k, v);
    }
}

更新 HashMap

  • entry & or_insert

    • entry 检查一个 k 是否有值,如果检测到值存在,则返回 value 的可变引用
    • or_insert 如果 k 为空则插入一个新值,并返回 value 的可变引用
    use std::collections::HashMap;
    
    fn main() {
      let mut config = HashMap::new();
    
      config.insert("a", "A");
      config.insert("b", "B");
      config.insert("c", "C");
      config.insert("d", "D");
    
      // entry 检查一个 k 是否有值,如果检测到值存在,则返回 value 的可变引用
      // or_insert 如果 k 为空则插入一个新值,并返回 value 的可变引用
      config.entry("a").or_insert("replace_A");
      config.entry("e").or_insert("E");
    
      /*
          {
              "a": "A",
              "b": "B",
              "c": "C",
              "e": "E",
              "d": "D",
          } 
       */
      println!("{:#?}", config);
    
      // 利用 entry 和 or_insert 的特性实现单词统计
      let words = "hello get get set clear good bad bad yep get";
    
      let mut count_map = HashMap::new();
    
      // split_whitespace 按照空格进行拆分,返回一个迭代器
      for key in words.split_whitespace() {
          let value = count_map.entry(key).or_insert(0);
          *value += 1;
      }
    
      /*
          {
              "get": 3,
              "set": 1,
              "hello": 1,
              "bad": 2,
              "good": 1,
              "yep": 1,
              "clear": 1,
          } 
       */
      println!("{:#?}", count_map)
    }
    

hash函数

  • HashMap默认的 hash 算法效率不是最高的,但有不错的安全性
  • 可以指定不同的 hasher 来切换 hash 算法

    • hasher 是指实现 BuildHasher trait 的类型

木木剑光
2.2k 声望2k 粉丝

Ant Design 社区贡献者