Rust基础(Option)

Option 表示值,如果有值则Some包装其值,否则返回None。

fn divide(a: f32, b: f32) -> Option<f32> {
    if b == 0.0f32 {
        None
    } else {
        Some(a / b)
    }
}
fn main() {
    let a = 1.0f32;
    let b = 2.0f32;
    let c = 0.0f32;
    let r = divide(a, b);
    println!("r = {:?}", r);
    println!("divide zero = {:?}", divide(a, c));
}

rust指针必须指向可用的位置,不是为null引用。比较之下,Rust有一个Option指针,类似于Option<Box>。在下面的例子,使用i32的Box创建一个Option。通过模式匹配实现对不同情况的处理:

fn check_optional(optional: Option<Box<i32>>) {
    match optional {
        Some(p) => {
            println!("解引用里面的值:{p}");
        }
        None => {
            println! {"Optional为空"};
        }
    }
}
fn main() {
    let optional1 = None;
    check_optional(optional1);
    let optional2 = Some(Box::new(99));
    check_optional(optional2);
}

Option的简化操作,如果我们要对向量中最后两个元素求和:

fn add_last_numbers(s: &mut Vec<i32>) -> Option<i32> {
    let a = s.pop();
    let b = s.pop();
    match (a, b) {
        (Some(x), Some(y)) => Some(x + y),
        _ => None,
    }
}
fn main() {
    let mut a = vec![1, 2, 3, 4];
    let b = add_last_numbers(&mut a);
    println!("b = {:?}", b);
}

我们也可以:


fn add_last_numbers(s: &mut Vec<i32>) -> Option<i32> {
    Some(s.pop()? + s.pop()?)
}

这里的?表达式将对Some解包,如果是None则结果还是None。这样就不用对Option的值层层匹配避免冗余操作。

Option常用方法

  • as_ref:将&Option<T>转换为Option<&T>
  • as_mut:转换&mut Option为Option<&mut T>。
  • as_deref:转换&Option为Option<&T::Target>。
  • as_deref_mut:转换&mut Option<T>Option<&mut T::Target>
  • as_pin_ref:转换Pin<&Option<T>Option<Pin<&T>
  • as_pin_ref:转换Pin<&Option<T>>Option<Pin<&T>>
  • as_pin_mut:转换Pin<&mut Option<T>>Option<Pin<&mut T>>
  • expect:如果为None则爆出给定的错误信息。
  • unwrap:如果为None则爆出错误信息否则解包Option里面的元素。
  • unwrap_or:如果为None则返回给定的值,否则解包。
  • unwrap_or_default:返回类型T的默认值。
  • unwrap_or_else:返回提供的值。是
  • ok_or:转换Some(b)Ok(b)NoneErr(err)
  • ok_or_else:转换Some(v)Ok(v)NoneErr的值。
  • transpose:转换Option的结果为Result。
  • filter:对Some(t)的t调用函数,如果为Option包含值则函数返回True,否则返回None。
  • map:使用提供的函数转换Option为Option,如果Option为Some则映射转换否则返回None。
  • map_or:如果Option是Some则返回Some的值,否则返回默认值。
  • map_or_else:如果是Some则使用函数,否则返回callback函数的调用结果。
  • zip:如果self是Some(s)提供了Option(o)返回Some((s,o)),否则返回None。
  • zip_with:调用提供的函数,如果Option是Some(o)提供的Some(s)则返回Some(f(s,o)),否则返回None。

逻辑运算:

方法 self(Option本身) 运算输入 运算输出
and None ignore(表示无论是什么输出都一样) None
and Some(x) None None
and Some(x) Some(y) Some(y)
or None None None
or None Some(y) Some(y)
or Some(x) ignore Some(x)
xor None None None
xor None Some(y) Some(y)
xor Some(x) None Some(x)
xor Some(x) Some(y) None

and_then和or_else方法接受函数输入,当有值的时候产生一个新的值,and_then方法生成一个Option不同于原来的Option类型。

方法 self function输入 function result 输出
and_then None 无输入 无计算 None
and_then Some(x) x None None
and_then Some(x) x Some(y) Some(y)
or_else None 无输入 None None
or_else None 无输入 Some(y) Some(y)
or_else Some(x) 无输入 无计算 Some(x)

and_then或者是or_else常用在pipeline调用的场景,pipeline中的一个状态计算失败则传递None,否则继续处理Some里面的值。

比较运算符:
如果T本身实现了PartialOrd然后Option将继承它的PartialOrd。结合这个顺序,None<Some,两个Some使用同昂的方法比较的时候比较的是其中的值。如果T也实现了Ord,然后可以Option也是相同的道理。

assert!(None < Some(0));
assert!(Some(0) < Some(1));

在Option上迭代:

  • into_iter:消耗Option,生成其中包含的值。
  • iter:生成一个无法修改的&T的值。
  • iter_mut:生成一个可变值的引用。
main() {
    let yep = Some(4);
    let nope = None;
    //chain方法调用into_iter生成迭代器,这里yep为Some(4)则将4取出
    let nums: Vec<i32> = (0..4).chain(yep).chain(4..8).collect();
    assert_eq!(nums, [0, 1, 2, 3, 4, 4, 5, 6, 7]);
    //chain方法调用into_iter生成迭代器,这里Nope为None则无法取出。
    let nums1: Vec<i32> = (0..4).chain(nope).chain(4..8).collect();
    assert_eq!(nums1, [0, 1, 2, 3, 4, 5, 6, 7]);
}

Option 实现了FromIterator trait:可以在Option的值上收集值进一个Option集合,如果Option本身有任何一个元素为None则结果为None。

fn main() {
    let v = [Some(2), Some(4), None, Some(8)];
    let res: Option<Vec<_>> = v.into_iter().collect();//包含一个None
    assert_eq!(res, None);
    let v = [Some(2), Some(4), Some(8)];
    let res: Option<Vec<_>> = v.into_iter().collect();
    assert_eq!(res, Some(vec![2, 4, 8]));
}

Option也实现了Product和Sumt rait,允许Option里面的元素累积和累和。

fn main(){
   let v = [None, Some(1), Some(2), Some(3)];
let res: Option<i32> = v.into_iter().sum();//包含有None,求和为None
assert_eq!(res, None);
let v = [Some(1), Some(2), Some(21)];
let res: Option<i32> = v.into_iter().product();
assert_eq!(res, Some(42));
}

原位修改Option:

  • insert:插入一个值,删除老值。
  • get_or_insert:获取当前值,如果为None则插入提供的值。
  • get_or_insert_default:获取当前值,插入T类型的默认值(必须实现Default)。
  • get_or_insert_with:获取当前值插入,如果为None则默认函数计算值。
    转换Option值的所有权:
  • take:获取Option的值得所有权,如果Option为None的使用None替代。
  • replace:获取Option值的所有权,如果有任何元素,使用Some(value)替代。
let msg = Some("howdy");

// Take a reference to the contained string
if let Some(m) = &msg {
    println!("{}", *m);
}

// Remove the contained string, destroying the Option
let unwrapped_msg = msg.unwrap_or("default message");

循环之前初始化结果为None:

enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) }

// A list of data to search through.
let all_the_big_things = [
    Kingdom::Plant(250, "redwood"),
    Kingdom::Plant(230, "noble fir"),
    Kingdom::Plant(229, "sugar pine"),
    Kingdom::Animal(25, "blue whale"),
    Kingdom::Animal(19, "fin whale"),
    Kingdom::Animal(15, "north pacific right whale"),
];

// We're going to search for the name of the biggest animal,
// but to start with we've just got `None`.
let mut name_of_biggest_animal = None;
let mut size_of_biggest_animal = 0;
for big_thing in &all_the_big_things {
    match *big_thing {
        Kingdom::Animal(size, name) if size > size_of_biggest_animal => {
            // Now we've found the name of some big animal
            size_of_biggest_animal = size;
            name_of_biggest_animal = Some(name);
        }
        Kingdom::Animal(..) | Kingdom::Plant(..) => ()
    }
}

match name_of_biggest_animal {
    Some(name) => println!("the biggest animal is {name}"),
    None => println!("there are no animals :("),
}
  • is_some:判断Option是否为Some。

   转载规则


《Rust基础(Option)》 bleedingfight 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Rust基础(常见的标准宏) Rust基础(常见的标准宏)
Rust中的标准宏 宏名称 功能 说明 concat_bytes 拼接字面量为一个字节切片Experimental Concatenates literals into a byte slice. 实验性(需要nightly版本)
2023-09-12
下一篇 
Rust三方库-actix Rust三方库-actix
ActixActix 是一个Rust异步Webserver,它提供了构建webserver需要的多种能力,包括路由、中间件、请求预处理、相应后处理等等。所有的actix server均围绕App构建,用于为资源和中间件注册路由。在相同的
2023-09-10
  目录