目录
- 一、三种常见集合
- 二、Vector
- 2.1 特性
- 2.2 创建并更新Vector
- 2.3 读取Vector中的元素
- 2.4 遍历元素
- 2.5 储存不同类型的值
- 三、字符串
- 3.1 概念
- 3.2 新建
- 3.2 更新
- 3.3 索引字符串
- 3.4 字符串切片
- 3.5 字符串遍历
- 四、哈希map
- 4.1 基本概念
- 4.2 新建哈希map
- 4.3 访问哈希map中的值
- 4.4 更新哈希map
一、三种常见集合
- 字符串(string)是
字符的集合
; - vector:一个挨着一个地储存一系列
数量可变
的值; - 哈希map(hash map):将值与一个特定的键(key)相关联;
其它类型的集合参见:https://rustwiki.org/zh-CN/std/collections
二、Vector
2.1 特性
- 允许在一个单独的数据结构中储存多个值;
- 所有值在内存中彼此相邻排列;
- vector 只能储存相同类型的值。
2.2 创建并更新Vector
- 使用
Vec::new()
创建; - 使用
vec!
宏创建; - 使用
push
压入数据;
fn main() {
let mut x = Vec::new(); //创建可变的空Vector
x.push(38); //压入数据
let y = vec![0, 5, 18, 19]; //使用宏创建,直接存入初始数据
// y.push(40); //非可变,不可压入
}
2.3 读取Vector中的元素
- 使用
&[i]
返回引用; - 使用
get
方法返回一个Option<&T>;
&[i]返回
fn main() {
let v = vec![1, 2, 3, 4, 5];
let v8 = &v[8];
}
上面的代码运行时会报错,根据提示可知,索引超出范围了。
get方法返回
fn main() {
let v = vec![1, 2, 3, 4, 5];
let v9 = v.get(9);
println!("v9 = {:#?}", v9);
}
上面的代码输出v9 = None
,代表没有找到,由于get
方法返回Option<&T>,所以可以使用match匹配;
完整示例
- 使用
get
时用match匹配,超出索引时输出错误信息
fn main() {
let v = vec![1, 2];
let third: &i32 = &v[1];
println!("The first element is {}", third);
match v.get(3) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
}
更多的信息参阅:https://doc.rust-lang.org/stable/nomicon/vec/vec.html
2.4 遍历元素
//遍历Vector
fn display_vec(src: &Vec<i32>)
{
for item in src{
println!("{}", item);
}
}
fn main() {
let mut v = vec![100, 32, 57];
display_vec(&v);
for item in &mut v{
*item += 10; //每一项都加10
}
display_vec(&v);
}
2.5 储存不同类型的值
- 一般来说vector存储的数据类型
必须相同
; - 可以使用
枚举的附加值属性
存储不同类型值;
下面的代码表示从Excel中获取一行数据值,这一行值有整数,浮点数及字符串,这样就能存储不同类型的值。
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
fn main() {
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
}
三、字符串
3.1 概念
- Rust的核心语言中只有一种字符串类型:str,即
字符切片&str
,它被储存在程序的二进制输出中; - String由标准库提供,它是
可增长、可变、有所有权以及UTF8编译的字符串类型
; - 通常说的“字符串”,一般是
string或者字符切片
; - 标准库中还包含一系列其他字符串类型,比如
OsString、OsStr、CString和CStr
,不同的后缀代表它是String或&str的变体;
3.2 新建
- 创建一个空的然后写入;
- 从字符串字面量转换;
- 将字符串字面量转换成String;
fn main() {
let a = String::new(); //创建空的
let b = String::from("hello"); //从字符串字面量转换而来
let c = "hello".to_string(); //将字符串字面量转换成String
}
字符串是UTF8编译的,可以包含任何正确编码的数据
不同语言的“你好"(还是中文的最好看)
fn main() {
let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
}
3.2 更新
- 使用
push_str
或push
附加; - 使用
+
或者format!
宏拼接;
附加更新
fn main() {
let mut s = String::new();
s.push('H'); //附加一个字符
s.push_str(" Zhong"); //附加一串字面量
println!("s = {}", s); //s = H Zhong
}
拼接更新
- 使用
+
拼接会转移运算符前面变更的所有权 - 运算符后面参数用
引用
format!
宏用起来更灵活,不会获取任何参数的所有权
fn main() {
let s1 = String::from("NiHao");
let s2: String = String::from("China!");
let s3 = s1 + &s2; //获取s1的所有权后拼接上s2的内容,返回所有权
let s4 = format!("{} {}, I love {}", s2, s2, s2);
// println!("s1 = {}", s1); //s1的所有权不在这里了,无法打印
println!("s2 = {}", s2); //s2 = China!
println!("s3 = {}", s3); //s3 = NiHaoChina!
println!("s4 = {}", s4); //s4 = China! China!, I love China!
}
3.3 索引字符串
Rust无法用索引获取字符串,如
fn main() {
let s1 = String::from("NiHao");
let x0 = s1[0];
}
报错信息如下
3.4 字符串切片
Rust不支持索引字符串,但是支持字符串切片,如
fn main() {
let s1 = String::from("NiHao");
println!("{} {}", &s1[..1], &s1[2..5]);
}
3.5 字符串遍历
chars
方法:返回字符bytes
方法:返回原始字节
fn main() {
let s1 = String::from("NiHao");
for c in s1.chars() {
println!("{}",c);
}
println!("************");
for c in s1.bytes() {
println!("{}",c);
}
}
运行结果
四、哈希map
4.1 基本概念
- 哈希map(hash map)使用
HashMap<K, V>
储存键值对; - 可以用于需要
任何类型作为键
来寻找数据; - 哈希map中所有的
键必须是相同类型,值也必须都是相同类型
; - 将诸如拥有
所有权的String
插入hash map,其所有权也会被转移
;
4.2 新建哈希map
- 使用
new
创建空的,然后使用insert增加元素; - 使用一个元组的vector的
collect
方法(其中每个元组包含一个键值对); - 使用collect方法时必须
显式指定
;
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new(); //创建空hash map,然后插入
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
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(); //由两个vector一对一组成hash map
}
所有权被改变示例
use std::collections::HashMap;
fn main() {
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
println!("field_name = {}", field_name);
println!("field_value = {}", field_value);
}
编译出错
4.3 访问哈希map中的值
- 通过get方法访问
- 遍历访问
get方法
- get方法返回
Option<V>
,结果被装进Some中,如果键没有对应的值,就会返回None。
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);
}
遍历方法
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
for (key, value) in &scores {
println!("{}: {}", key, value);
}
}
运行结果
Yellow: 50
Blue: 10
4.4 更新哈希map
- 覆盖值
- 不存在时插入
- 根据旧值更新三种情况
覆盖值
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 50); // 强制更新
println!("{:?}", scores); //{"Blue": 50}
}
不存在时插入
- entry可以将想要检查的键作为参数,返回枚举
Entry
; or_insert
方法在键对应的值存在时就返回这个值的可变引用(&mut V
),如果不存在则将参数作为新值插入并返回新值的可变引用- 使用
entry配合or_insert
可以达到目的;
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.entry(String::from("Yellow")).or_insert(50); //”Yellow"如果不存在,插入 "Yellow:50"
scores.entry(String::from("Blue")).or_insert(50); //”Blue"如果不存在,插入 "Blue:50"
println!("{:?}", scores); //{"Yellow": 50, "Blue": 10}
}
根据旧值更新
代码统计单词在一句话中出现的次数
use std::collections::HashMap;
fn main() {
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); //{"world": 2, "wonderful": 1, "hello": 1}
}