Rust: Common Collections

Common Collections

Vector

创建Vector

let x: Vec<i32> = Vec::new();// 创建Vector
// Vector<T> 中类型一样
// 可以显示声明 T 类型, 也可以编译器推断出 type

// 使用宏 vec! 来创建初始Vec<T>
let x = vec![1, 2, 3];

添加元素

// 添加元素
let mut v = Vec::new();
v.push(1);
v.push(2);
for x in v.iter() {
    println!("{}", x);
}

删除Vector

当 Vector 离开作用域时会被删除

访问 Vector 中的元素

1.索引 data_name[index]

2.get data_name.get(index)

let x = vec![1, 2, 3, 4];
println!("{}", x[3]);

// v.get(index) 返回 Option<T>
match x.get(3) {
    Some(val) => println!("{}", val),
    None => println!("index out of bound"),
};

当 index 超出范围时
data_name[index] 会造成 panic
data_name.get(index) 会返回 None

Ownership

let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);
println!("{}", first);
// cannot borrow `v` as mutable because it is also borrowed as immutable

记得Ownership 的特性吗? 不能同时有可变引用,和不可变引用

first 已经对 v 不可变引用, push 就不能操作了

可变引用的示例

let mut v = vec![1, 2, 3, 4, 5];
for i in &mut v {
    *i += 1;
}

for i in v.iter() {
    println!("{}", i);
}

Vector + enum

Vector + enum 可以实现 Vector 存不同类型

enum Kind {
    int(i32),
    double(f64),
    string(String),
}

let x = vec![Kind::int(1), Kind::double(1.0), Kind::string(String::from("2024"))];
// enum 中的所有类型必须明确,这样编译器才可以确定大小
// 也可用 trait 超出本节范围,暂时不提

String

创建 String

let mut x = String::new();
let y = String::from("ABC");

添加元素

x.push('A');
x.push_str("ABC");
x += "A";// str 类型
x += &y;// 采用&String
println!("{}", x);// AABCA
println!("{}", y);// OwnerShip 不变

to String

// type -> String
// String::from();
// str_data_name.to_string();
let x = String::from("2024");// str -> String
let y = "2024".to_string();// str -> String
let z = 1;
let s = z.to_string();// i32 -> String

字符串拼接 +

let s1 = String::from("20");
let s2 = String::from("24");
let s3 = s1 + &s2;// 注意只有第一个不用& 等价于把&String -> &str
// println!("{}", s1);// Error! borrow of moved value: `s1`
println!("{}", s2);// right 
println!("{}", s3);// right

format!

format! 拼接字符串 不会获得String的所有权

let s1 = String::from("20");
let s2 = String::from("24");
let s3 = format!("{}{}", s1, s2);
println!("{}", s1);// right
println!("{}", s2);// right 
println!("{}", s3);// right

特性

String 不支持 [index] 访问元素

String len() 方法返回的是字节数,一般一个字母是一个字节

let x = String::from("SCUT");
let y = String::from("华工");
println!("{} {}", x.len(), y.len());// 输出 4 6 // 汉字有些占 2 字节, 有些占 3 字节

回到字符串切片

// 字符串切片只能沿着 char 边界切
// 比如 华 占两个字节,对中间切会造成 panic
let s = &y[0..1];
println!("{}", s);
// byte index 1 is not a char boundary; it is inside '华' (bytes 0..3) of `华工`

遍历

遍历 String
chars() 从字符角度
bytes() 从字节角度

for x in y.chars() {
    println!("{}", x);
}
/*
    华
    工
     */

for x in y.bytes() {
    println!("{}", x);
}
/*
    229
    141
    142
    229
    183
    165
     */

// Error!
for x in y {

}// 没有 iter

HashMap

数据在 heap 上

不在 Prelude 中

同一个 HashMap 中 K 类型必须一样

创建

let mut x: HashMap<String, i32> = HashMap::new();

可以显示指明也可以编译器推断

添加元素

insert 方法,其返回 Option<T>

x.insert(String::from("SCUT"), 2024);
// If the map did not have this key present, None is returned.
// If the map did have this key present, the value is updated, and the old value is returned. 

访问元素

get 方法, 返回 Option<T>

let mut map = HashMap::new();
let k = String::from("SCUT");

match map.get(&k) {
        Some(x) => println!("{}", x),
        None => println!("None"),
};

更新 HashMap

// insert 插入时,如果对应的 key 存在,将替换对应的 val

检查 key

contains_key 方法 返回 bool

if map.contains_key(&k) {
    println!("YES");
}

entry 方法 返回 enum Entry : 代表值是否存在

or_insert()

如果 key 存在 返回 val 的可变引用

如果 key 不存在 插入后返回其可变引用

let e = map.entry(&k);
e.or_insert(&v);

// 链式调用
let e = map.entry(&k).or_insert(&v);

遍历

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

Ownership

对于实现了 copy trait 的类型,值会被复制到 HahaMap

对于未实现 copy trait 的类型,其所有权会交给 HashMap

let mut map = HashMap::new();
let k = String::from("SCUT");
let v = String::from("2024");
map.insert(k, v);
println!("{} {}", k, v);// Error!
// move occurs because `v` has type `String`, which does not implement the `Copy` trait
let mut map: HashMap<&String, &String> = HashMap::new();
let k = String::from("SCUT");
let v = String::from("2024");
map.insert(&k, &v);// &String 形式
println!("{} {}", k, v);// correct
// 在 HashMap 有效期间, 被引用的值必须保持有效