匹配、向量组、~~哈希表~~和错误处理。
先过一遍基础,之后写东西遇到问题再单拎出来写整合博文……这么想的。
2022-01-16:哈希表移到了 Collection 合集里。
匹配和枚举
Option 和 Result
enum Fruit {
Apple,
Banana,
Pear,
Orange,
}
fn show_fruit(fruit: Fruit) -> String {
match fruit {
Fruit::Apple => "apple".to_string(),
Fruit::Banana => "banana".to_string(),
Fruit::Pear => "pear".to_string(),
Fruit::Orange => "orange".to_string(),
}
}
fn main() {
let myfavorite = Fruit::Orange;
println!("my favorite fruit is {}", show_fruit(myfavorite));
}
对于匹配时没有匹配上的项目留下的默认选项:_ => <exp>
,和 Elm 一样。
利用类型选项来进行匹配(类似 Elm 的Maybe
)。
fn main() {
print_number(Some(32));
print_number(None);
}
fn print_number(str: Option<i32>) {
match str {
Some(s) => println!("你输入的数字是:{}", s),
None => println!("输入为空!")
}
}
可以对枚举成员添加属性描述:
enum Message{
Id(u32),
Position {x:i32,y:i32},
Msg(String),
Color(i32,i32,i32)
}
match message {
Message::Id(id) => ...
}
if let 和 while let
有时需要这样的使用场景
if let Some(i) = value {
...
}
while let Some(i) = value{
...
}
while let
和 if let
将 value
解构到 Some(i)
中。如果value
是None
则为否/跳过。
向量 | Vectors
fn main() {
//向量组
let mut v: Vec<i32> = Vec::new();
//向向量组内添加
v.push(1);
//根据内容创建向量组
let v2 = vec![1, 2, 3];
//读取数据,
let data: &i32 = &v2[0];
let data2: std::option::Option<&i32> = v2.get(0); //可能 get 到的是 None
//也可以通过 v2[0] 直接取值。
//但如果越界则会直接 panic,使用 get 则可以处理“如果越界”的情况。
}
迭代:
for i in &v2{
println!("{}", i);
}
for i in &mut v {
*i +=1; //更改可变引用所引用的值,使用解除引用符号(*)
println!("{}", i);
}
复制
由于 Rust 默认不可变,所以如下的代码片段编译不会通过:
fn main(){
let v = vec![1,2,3];
v[0] = 3;
println!("{:?}",v)
}
考虑使用to_vec
复制内容:
fn main() {
let v = vec![1, 2, 3];
let v2 = &mut v.to_vec();
v2[0] = 3;
println!("{:?}", v);
println!("{:?}", v2);
}
编译通过,运行结果:
[1, 2, 3]
[3, 2, 3]
pub fn to_vec(&self) -> Vec<T, Global> where
T: Clone,
Copies self into a new Vec.
复制切片 (slice):
let mut x = vec![0; 3]; //[0,0,0]
let y = vec![1, 2, 3, 4, 5, 6, 7];
x.clone_from_slice(&y[0..3]);
println!("{:?}", x); // [1, 2, 3]
错误处理
Rust
有一个panic!
宏。碰到无法处理的错误时,该宏运行,程序将输出错误信息并清理堆栈,退出程序。
//对于可能出现的错误,使用 Result 类型处理。
//enum Result<T, E> {
// Ok(T),
// Err(E),
// }
fn main() {
let input1 = "abcde";
let _number: i32 = match input1.parse() {
Ok(num) => num,
Err(_) => panic!("该字符串不是数字!"),
};
//thread 'main' panicked at '该字符串不是数字!', ./error.rs:13:19
}
错误的再匹配:error.kind
查看错误类型。
简写:
//如果失败会触发 panic(由 unwrap 触发)
let _n1: i32 = String::from("abced").parse().unwrap();
//thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', ./error.rs:11:50
使用expect
可以提供自定义错误信息。
let _n2: i32 = String::from("abced").parse().expect("non-number");
//thread 'main' panicked at 'non-number: ParseIntError { kind: InvalidDigit }', ./error.rs:11:50
?
接在Result
型后面,如果 Ok 则返回值,不然返回并传播 Err(退出整个函数)。所以整个函数的返回值是Result
,例如Ok(())
。
use std::num::ParseIntError;
fn pars() -> Result<i32, ParseIntError> {
let n3 = "abcde";
let n4 = n3.parse::<i32>()?;
Ok(n4)
}
//调用 pars() 并打印结果
//Err(ParseIntError { kind: InvalidDigit })
Box<dyn std::error::Error>
可以接受任何类型的error
。在函数中,可以把多种类型的错误展成此一种错误。dyn 是trait
对象的前缀,说明对trait
上方法是动态调用的。
虽然使用 ?
返回的应该是同一种错误。但可以让类型定义Trait
std::convert::From<>
来自动转换。
迭代器 | Iterator
迭代器 (Iterator)。可实现对序列化对象的遍历。详细可用方法
所有Iterator
均实现一个next
方法以索引到下一个对象(Some
或者None
)。
迭代器的消耗:可以理解为迭代器内部维护着目前的迭代情况。需要注意的是,迭代器如果不消耗,设定的方法也不会运行。
collect
将迭代器转换回集合。有时需要注明类型,例a.iter().collect::<String>()
。last
运行(消耗)迭代器,返回最后一个元素。
按字符迭代字符串:
let chars: Vec<char> = str.chars().collect();
- 主要是 《The Book》 的读书笔记。
- Rustlings 的做题感想
- 封面图片:Photo by rompalli harish from Pexels