rust进阶-基础.2.Option类型
Option类型是Rust中非常重要的一个类型,和Result也类似。
本文主要根据文档:枚举类型Option编写
主要阐述以下内容:
1.Option和Result比较
2.Option的主要方法
3.示例
1.Option和Result比较
以下内容来自于文心一言
特性 | Option | Result |
---|---|---|
目的 | 表示一个值可能存在(Some(T) )或不存在(None ),避免空指针异常。 |
表示一个操作可能成功(Ok(T) )或失败(Err(E) ),需携带错误信息。 |
典型场景 | 集合查找(如Vec::get )、可选字段(如链表节点的next 指针)。 |
文件I/O、网络请求、解析验证(如JSON反序列化)。 |
错误处理 | 仅表示值的存在性,无法传递错误上下文(如None 无法区分“未找到”与“空输入”)。 |
通过Err(E) 携带错误类型,支持精细化错误处理(如区分“文件不存在”与“权限不足”)。 |
这些应该是主要的差异。
Result可以传递错误信息。
2.Option的主要方法
3.示例
use std::iter::Sum;
#[derive(Debug)]
struct Area {
width: u32,
height: u32,
flag: bool,
}
impl Default for Area {
fn default() -> Self {
Area {
width: 103,
height: 2012,
flag: true,
}
}
}
impl Iterator for Area {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.flag {
let area = self.width * self.height;
self.flag = false;
Some(area)
} else {
None
}
}
}
/**
* 实现这个以便直接比较两个Area对象的大小,因为Rust不允许直接对结构体进行比较
*/
impl PartialEq for Area {
fn eq(&self, other: &Self) -> bool {
let self_area = self.width * self.height;
let other_area = other.width * other.height;
self_area == other_area
}
}
/**
* 实现这个以便直接比较两个Area对象的大小,因为Rust不允许直接对结构体进行比较
*/
impl PartialOrd for Area {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
let self_area = self.width * self.height;
let other_area = other.width * other.height;
Some(self_area.cmp(&other_area))
}
}
impl Area {
fn area(&self) -> u32 {
self.width * self.height
}
}
#[derive(Debug)]
struct Exam{
test_time:u32,
score:u32,
}
impl Sum for Exam{
fn sum<I>(iter: I) -> Self
where I: Iterator<Item = Exam>{
let mut total=Exam{test_time:0,score:0};
for x in iter{
if total.test_time==0 {
total.test_time = x.test_time;
}
total.score += x.score;
}
total
}
}
fn main() {
println!("\n-- 测试直接操作 \n");
let _r = test_direct_add(Some(1), Some(2));
//两个同种Option直接比较
println!("\n-- 测试直接比较 \n");
test_direct_compare();
//
println!("\n-- 测试抽取值相关的方法 \n");
test_extract_value();
println!("\n-- 测试修改相关的方法 \n");
test_modify();
println!("\n-- 测试操作相关的方法 \n");
test_operate();
println!("\n-- 测试查询 \n");
let value = Some(String::from("健康饮食。66天养成一个习惯"));
test_query(value);
println!("\n-- 测试引用相关的方法 \n");
test_ref();
println!("\n-- 测试转换相关的方法 \n");
test_transform();
}
/**
* 两个Option可以直接比较,如果二者都实现了PartialOrd(Ord也可以)
* 那么可以使用基本的比较运算符进行比较
*/
fn test_direct_compare(){
println!("要求其中的T实现PartialOrd");
let d=Area::default();
let a=Area{width: 10, height:20, flag:true};
if d>a{
println!("{:?}>{:?}",d,a);
}else{
println!("{:?}<={:?}",d,a);
}
}
/**
* 直接使用?操作符,如果Option是Some则返回里面的值,如果是None则返回None。
*/
fn test_direct_add(a: Option<i32>, b: Option<i32>) -> Option<i32> {
let result=Some(a? + b?);
println!("{}+{}={}",a.unwrap(),b.unwrap(), result.unwrap());
result
}
/**
* 取值后,通常而言,原来的变量不可在引用
*/
fn test_extract_value() {
//测试unwrap_or 和unwrap_or_else
//unwrap_or_else 要求参数是一个FnOnce类型的匿名函数,且返回T类型值。
let book = None;
let book_name = book.unwrap_or("沈氏四声考".to_string()); //unwrap_or获取默认值
println!("None unwrap_or后,值={}", book_name);
let book = Some("沈氏四声考".to_string());
let book1=Some("沈氏四声考".to_string());
let book_name = book.unwrap_or_else(|| "沈氏四声考?".to_string()); //unwrap_or获取默认值
println!("{:?}中的值通过unwrap_or_else={}", book1,book_name);
//测试unwrap_or_default,此方法要求T类型实现Default trait,所以如果没有值情况下,返回的是该类型的默认值。
let area: Option<Area> = None;
let area_default = area.unwrap_or_default(); //获取默认值
println!("Area是一个None,默认={:?}", area_default.area());
//测试take,take_if,replace等方法。
// take --take(&mut self) -> Option<T> ,原来的变为None
// take_if take_if<P>(&mut self, predicate: P) -> Option<T>。p:FnOnce(&mut T) -> bool
// 在取的时候,可以对数据进行修改
// replace replace(&mut self, value: T) -> Option<T>,替换原来的值,返回来源的值。关键是原来的保留,新的也存在.
let mut a=Some(10);
let ta=a.take(); //取出值,并把原来的值设置为None。
println!("{:?}被取出后={:?}",ta, a);
//take_if 要求参数是一个FnOnce类型的匿名函数,且返回bool类型值。
let mut b=Some(20);
let tb=b.take_if(|x| *x>30);
println!("{:?}被取出后={:?}",tb, b);
//replace 要求参数是T类型值。
let mut c=Some(30);
let old=c.replace(40);
println!("c={:?},old={:?}", c,old);
}
/**
* 测试如何修改一个Option内含值
*/
fn test_modify(){
//方式有多种,已知的略。
println!("演示insert,get_or_insert方法。");
//此处介绍insert,get_or_insert方法。
//insert(&mut self, value: T) -> &mut T,会替换原来的值(如果有)
//get_or_insert(&mut self, value: T) -> &mut T , 如果没有值,则插入,否则取出已有的值。
//不太明白这些方法有什么使用场景?
let mut a=Some(10);
let b=a.insert(20);
*b+=10;
println!("b={:?}", b);
println!("a={:?}", a.unwrap());
let mut a1=None;
let c=a1.get_or_insert(30);
println!("c={:?}", c);
}
fn test_operate(){
//测试and - and只要有一个是None,则返回None,否则返回参数值
//不知道这方法有何用? 就是用于测试两个Option?
//除了and,还有or和xor。
//or取其中一个值,如果有一个值是Some,则取之。如果变量本身是Some,则返回本身
//xor和or基本一样,不同的是如果x.xor(y)中x,y都是Some,则返回None。
let a = Some(10);
let b:Option<u32> = None;
let c=a.and(b);
println!("c={:?}", c);
//测试and_with
let fx=|_|{Some(100)};
let c=a.and_then(fx);
println!("c={:?}", c);
}
fn test_query(value: Option<String>) {
if value.is_some() {
println!("{}", value.unwrap());
} else {
println!("没有值");
}
}
/**
* rust可以象js那么随意,在函数中定义函数
*/
fn test_ref() {
fn validate_type(val: Option<&String>) {
match val {
Some(v) => println!("{}", *v),
None => println!("没有值"),
}
}
let a = Some(String::from("今君往死地,沉痛迫中肠"));
let ref_a = &a; // &Option<String>
let ref_a_ref = ref_a.as_ref(); //Option<&String>
validate_type(ref_a_ref);
}
fn test_transform() {
let book: Option<i32> = None;
let book_name = book.ok_or(-1);
println!("{:?}", book_name);
//测试无聊函数filter等。
//filter函数要求T本身实现Iterator trait. struct转为迭代器本身就是很罕见的。
let score = Some(10);
let dd = score.filter(|x| *x >= 10); // filter要求FnOnce的参数是&T类型。
println!("过滤后,{:?}", dd.unwrap());
//测试map方法。
//map返回Option<U>
let area_default= Some(Area::default());
println!("默认值={:?}", area_default);
let area_new = area_default.map(|a| {
a.area()
});
println!("area_new={:?}", area_new);
//测试合并 x.zip(y)=Some((x,y)),如果其中一个为None则返回None。
let rubbish=score.zip(area_new);
println!("合并结果1={:?}", rubbish);
let rubbish=book.zip(score);
println!("合并结果2={:?}", rubbish);
let rubbish=score.zip(book);
println!("合并结果3={:?}", rubbish);
//迭代行为,这是一种自动行为,不需要显式调用。
let score:[u32;3]=[10,20,30];
let score_vec:Vec<u32>=score.into_iter().chain(Some(90)).collect();
println!("合并结果4(利用迭代器)={:?}", score_vec);
//如果T实现了Sum,Product等trait,则可以调用sum,product等方法。 但是如果有一个成员为None,则返回None。
let score1=Some(Exam{
score:10,
test_time:1994
});
let score2=Some(Exam{
score:20,
test_time:1994
});
let score_arr = [score1,score2];
let sum:Option<Exam>=score_arr.into_iter().sum();
println!("总成绩={:?}", sum);
//收集
//收集Option还是有一些价值的.
//注意:只要其中过一个是None,则返回None。
let v:[Option<u32>;4] = [Some(2), Some(4), None, Some(8)];
let res: Option<Vec<u32>> = v.into_iter().collect();
println!("通过collect收集的结果5(收集)={:?}", res.unwrap_or_default());
//展示一个不是None的集合,返回的还是Option<Vec<T>>,所以需要unwrap一下。
let v:[Option<u32>;4] = [Some(2), Some(4), Some(880), Some(8)];
let res: Option<Vec<u32>> = v.into_iter().collect();
println!("通过collect收集的结果5(收集)={:?}", res.unwrap());
}
输出示例:
本文来自博客园,作者:正在战斗中,转载请注明原文链接:https://www.cnblogs.com/lzfhope/p/18884761