概述
集合都和存储在 heap 中
1. Vector
- 类型为 Vec
- 由标准库 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 的包装
- 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 的类型