赞
踩
Vec,也被称为 vector。vector 允许我们在一个单独的数据结构中储存多于一个的值,它在内存中彼此相邻地排列所有的值。vector 只能储存相同类型的值。它们在拥有一系列项的场景下非常实用
通过使用new进行创建
其实更好的是我们需要指定其中的类型
let a = Vec::new();
let a: Vec<i32> = Vec::new();
Rust提供了一个宏vec!
用于快速创建Vec并指定其中的元素
let a = vec![];
通过使用push向Vec中添加元素
fn main() {
let mut a = vec![];
a.push(65);
a.push(100);
println!("{:?}", a);
}
fn main() {
let mut a = vec![];
a.push(65);
a.push(100);
for item in a {
println!("{:?}", item);
}
}
我们直接通过如数组一样的方式直接使用[]
就可以获取元素,或者可以通过使用get方法进行获取,但是get方法不会出现数组越界的问题,若越界则根据轮子公式:真实索引位置 = 原始索引位置 % 容量长度
let ele = &a[1];
let ele = a.get(1)
vector 只能储存相同类型的值。这是很不方便的;绝对会有需要储存一系列不同类型的值的用例。幸运的是,枚举的成员都被定义为相同的枚举类型,所以当需要在 vector 中储存不同类型值时,我们可以定义并使用一个枚举
fn main() {
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
}
哈希 map(hash map)。HashMap<K, V> 类型储存了一个键类型 K 对应一个值类型 V 的映射。它通过一个 哈希函数(hashing function)来实现映射,决定如何将键和值放入内存中。很多编程语言支持这种数据结构
通过使用键就可以找到值
首先引入use std::collections::HashMap;
通过new构建即可,当然更好是要指明存储类型
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
}
通过使用insert方法向map中增加元素,增加的元素必须要使用一样的类型(当然应用枚举也可以存储不同类型)
map.insert("1", 1);
map.insert("2", 2);
println!("{:#?}", map);
我们通过使用get获取到的是Option<&T>
若没有值则返回None,然后使用copied方法获取去除值引用的Option<T>
接着调用 unwrap_or ,若没有该键所对应的项时将其设置为零
let a = map.get("1").copied().unwrap_or(0);
在map中遍历得到的应该是键值对的形式
for (k, v) in &map {
println!("{}", k);
println!("{}", v);
}
通过insert插入一个原始HashMap中有的键名,即可实现覆盖
map.insert("1", 1);
map.insert("1", 2);
entry 函数的返回值是一个枚举,Entry,它代表了可能存在也可能不存在的值。通过or_insert表示没有的时候就插入,有就不做操作
map.entry(String::from("1")).or_insert(1);
fn main() {
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!("{:?}", map);
}
错误是软件中不可否认的事实,所以 Rust 有一些处理出错情况的特性。在许多情况下,Rust 要求你承认错误的可能性,并在你的代码编译前采取一些行动。这一要求使你的程序更加健壮,因为它可以确保你在将代码部署到生产环境之前就能发现错误并进行适当的处理。
Rust 将错误分为两大类:可恢复的(recoverable)和 不可恢复的(unrecoverable)错误。对于一个可恢复的错误,比如文件未找到的错误,我们很可能只想向用户报告问题并重试操作。不可恢复的错误总是 bug 出现的征兆,比如试图访问一个超过数组末端的位置,因此我们要立即停止程序。
Rust没有异常,对应有Result<T,E>
用于处理可恢复的错误
对于不可处理的使用panic!宏
出现不可恢复的错误,我们要求立即停止程序并告知用户错误信息,这时候我们可以应用panic!宏进行处理,例如在无法打开文件读取的时候,很适合!
panic!("错误提示信息")
当出现 panic 时,程序默认会开始 展开(unwinding),这意味着 Rust 会回溯栈并清理它遇到的每一个函数的数据,不过这个回溯并清理的过程有很多工作。另一种选择是直接终止(abort),这会不清理数据就退出程序
我们通过配置panic为abort采取直接终止不展开
[profile.release]
panic = 'abort'
程序的开发者认为一个错误是不可能恢复处理的就直接panic!决定权在开发者手中
在圣经中给出了如下场景适合使用panic
https://kaisery.github.io/trpl-zh-cn/ch09-03-to-panic-or-not-to-panic.html
大部分错误并没有严重到需要程序完全停止执行。有时,一个函数会因为一个容易理解并做出反应的原因失败
首先我们认识一下Result枚举
enum Result<T, E> {
Ok(T),
Err(E),
}
枚举中有两个字段,Ok和Err,很容易理解
那么设置了Err就要相应进行处理,我们可以通过使用match匹配到Err进行特殊处理
fn run_err(a: i32) -> Result<(),&'static str> {
if a > 5 {
return Err("err");
}
return Ok(());
}
fn main() {
let test_err = run_err(6);
match test_err {
Ok(()) => println!("success"),
Err(err) => println!("{}", err)
}
}
当然你也可以单独处理Err情况(if-let)
if let Err(err) = test_err {
println!("{}", err);
}
使用Result
虽然交给调用者进行处理但是不代表调用者不抛出panic,为了更简便,所以应声几种简单的形式
当编写一个其实先会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择让调用者知道这个错误并决定该如何处理。这被称为 传播(propagating)错误,这样能更好的控制代码调用,因为比起你代码所拥有的上下文,调用者可能拥有更多信息或逻辑来决定应该如何处理错误。
其实前面的这个示例其实就是传播了错误return Err("err");
fn run_err(a: i32) -> Result<(), &'static str> {
if a > 5 {
return Err("err");
}
return Ok(());
}
fn main() {
let test_err = run_err(6);
}
?运算符是传播错误的简写方式
下面的例子中我们将run_err中的错误传递到deal_err中,最后传到main中进行处理
fn run_err(a: i32) -> Result<(), &'static str> { if a > 5 { return Err("err"); } return Ok(()); } fn deal_err() -> Result<(), &'static str> { let a = run_err(6)?; Ok(a) } fn main() { let err_msg = deal_err().unwrap_err(); println!("{}",err_msg); }
如果 Result 的值是 Ok,这个表达式将会返回 Ok 中的值而程序将继续执行。如果值是 Err,Err 中的值将作为整个函数的返回值,就好像使用了 return 关键字一样,这样错误值就被传播给了调用者。
? 运算符只能被用于返回值与 ? 作用的值相兼容的函数。因为 ? 运算符被定义为从函数中提早返回一个值
Result<(返回类型),Box<dyn Error>>
Box<dyn Error>
类型是一个 trait 对象,可以将 Box<dyn Error>
理解为 “任何类型的错误”。在返回 Box<dyn Error>
错误类型 main 函数中对 Result 使用 ? 是允许的,因为它允许任何 Err 值提前返回。即便 main 函数体从来只会返回 std::io::Error
错误类型,通过指定 Box<dyn Error>
,这个签名也仍是正确的,甚至当 main 函数体中增加更多返回其他错误类型的代码时也是如此。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。