《Rust权威指南》学习笔记之第8章 通用集合类型
集合数据类型,数据存储在堆上,可以增删。
- 动态数组(vector)可以连续存储任意多个相同类型的值。
- 字符串(string)是字符的集合。
- 哈希映射(hash map)值关联到特定键上,映射(map)的特殊实现。
动态数组
Vec<T>
创建
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
更新
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
销毁
{
let v = vec![1, 2, 3, 4];
}
读取动态数组中的元素
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {}", third);
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element.", third),
}
let v = vec![1, 2, 3, 4, 5];
let does_not_exist = &v[100]; //panic
let does_not_exist = v.get(100); //None
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0]; //不可变引用
v.push(6); //可变引用
println!("The first element is {}", first);//error
遍历
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;;
}
枚举存储多个类型值
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
]
字符串存储UTF-8文本
字符串基于字节的集合,使用UTF-8编码.
字符串是什么
核心部分只有一种字符串类型,字符串切片str,常以借用形式&str出现。
标准库中String,OsString,OsStr, CString, CStr。
创建新字符串
let mut s = String::new();
let data = "initial contents"; //&str
let s = data.to_string();
let s = "initial contents".to_string();
let s = String::from("initial contents");
更新字符串
let mut s1 = String::from("foo");
let s2 = "bat"
s1.push_str(s2);
println!("s2 is {}", s2);
s1.push('1');
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; //s1已被移动
//fn add(self, s: &str) -> String
编译器可以自动将&String类型的参数强制转换为&str类型,解引用强制转换技术,将&s2转换为了&s2[…]。
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("tce");
//不会夺取任何参数的所有权
let s = format!("{}-{}-{}", s1, s2, s3);
字符串索引
let s1 = String::from("hello");
let h = s1[0]; //错误,Rust字符串不支持索引
内部布局
String是基于Vec<u8>的封装类型。
let len = String::from(“Hola”).len(); //4
let len = String::from(“你好”).len(); //?
字节、标量值及字形簇
字符串切片
let s1 = String::from("hello");
let h = &s1[0..4];
遍历字符串
for c in "你好world".chars() {
println!("{}", c);
}
for b in "你好world".bytes() {
println!("{}", b);
}
哈希映射中存储键值对
HashMap<K, V>,内部实现中使用了哈希函数。哈希(hash)、映射(map)、对象(object)、哈希表(hash table)、字典(dictionary)、关联数组(associative array)等。所有键相同类型,所有值相同类型。
创建哈希映射
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
use std::collections::HashMap;
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
哈希映射与所有权
实现了Copy trait类型,如i32,值会被简单复制;String这种持有所有权类型,值和所有权会被转移给哈希映射。
use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
//field_name和field_value失效。
引用插入哈希映射,不会被移动。这些引用所指向的值必须要保证,在哈希映射有效时自己也是有效的。
访问哈希映射中的值
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name);
match score {
None => println!("None"),
Some(i) => println!("{}", i),
}
for (key, value) in &scores {
println!("{}: {}", key, value);
}
println!("Hello, world!");
}
更新哈希映射
覆盖旧值
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
只在键无值时插入数据
use std::collections::HashMap;
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);
基于旧值来更新值
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!("{:?}", scores);
哈希函数
为了提供抵御拒绝服务攻击(DoS,Denial of Service)的能力,HashMap使用了默认哈希函数。可以通过实现BuildHasher trait的类型,自定义哈希函数。