rust中的map_or()和map_or_else()函数详解

Option<T>Result<T,E>中都定义了map_or/map_or_else函数,函数内部通过match模式匹配,快速提取Option/Result内含的值,并进行进一步的处理。

map_or()函数

先来看看Option<T>map_or函数的定义:

pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
    match self {
        Some(t) => f(t),
        None => default,
    }
}

第一个参数为self,表明map_orOption对象的成员方法(不是通过结构名称可以直接调用的静态方法)。
第二个参数default,是调用者传入的一个默认返回值,跟map_or()的返回值类型相同,都是泛型类型U。
Option对象本身是None时,会将此default作为map_or()的返回值返回出去。
第三个参数f,其类型F是带一个T类型输入参数,返回U类型的FnOnce函数/闭包。其中T类型就是Option<T>中的泛型类型T。
map_or最终返回的是U类型。

关于FnOnce的详细解释,可以参考:Rust 08:函数和闭包(FnOnce、FnMut、Fn)

可以看到,map_or内部封装了一个match匹配,可以在链式调用中,方便地提取Option中的值:

  • 如果本身是Some(t),那么函数调用结果f(t)将会被作为最终的返回值。
  • 如果本身是None,直接返回传给map_or的第一个参数(这里把self当做第0个参数)作为最终的返回值。

接下来,通过定义如下一个is_even()函数来判断一个Option<i32>是不是偶数(None不算偶数)。以此来熟悉map_or的用法:

// 对于一个Option<i32>类型的x,如果x是None,直接返回传给map_or的第一个参数值(false),
// 如果x中有值,则会通过第二个闭包进行处理:i32的值是偶数返回true,是奇数返回false。
fn is_even(x: Option<i32>) -> bool {
    x.map_or(false, |x|x%2==0)
}
println!("{}", is_even(None));//false
println!("{}", is_even(Some(1)));//false
println!("{}", is_even(Some(2)));//true

map_or_else()函数

map_or_elsemap_or不同的是,第一个参数也是FnOnce函数(不同的是,这是一个没有输入的闭包,因为当前只有一个None可用,没必要有输入),在match遇到None时,会调用此函数,而不是直接返回一个默认值。

fn my_unwrap(x: Option<u8>) -> i32 { 
    x.map_or_else(||-1, |x|x as i32)
}
println!("{}", my_unwrap(None));//-1
println!("{}", my_unwrap(Some(1)));//1
println!("{}", my_unwrap(Some(2)));//2

实战:判断递增列表

定义一个函数,判断一个列表中的数是否是递增的(要求用map_or来实现):

fn is_ascending(x: &Vec<i32>) -> bool {
    let mut iter = x.iter();
    // 取出迭代器中第一个元素进行map_or
    iter.next().map_or(true, |mut prev| {
    	// 遍历迭代器中除第一个元素外,其余的元素
        for cur in iter {
            if cur >= prev {
                prev = cur;
            } else {
                return false;
            }
        }
        true
    })
}
println!("{}", is_ascending(&vec![]));//true
println!("{}", is_ascending(&vec![1,2,5]));//true
println!("{}", is_ascending(&vec![9,2,5]));//false

补充

Result<T,E>中的map_or/map_or_else也是同样的用法。不同之处,仅仅在于Option<T>中用于匹配None的情况,在Result<T,E>中被换成了Err(e)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: `unwrap_or` 和 `unwrap_or_else` 都是用于从 `Result` 对象获取值的宏。 当 `Result` 对象是 `Ok` 时,两者都会返回 `Ok` 的值。但是当 `Result` 对象是 `Err` 时,两者的行为不同: - `unwrap_or` 将返回一个默认值。这个默认值是宏的参数,在调用 `unwrap_or` 时就已经确定了。 - `unwrap_or_else` 将调用一个闭包,并返回闭包的结果。这个闭包是宏的参数,在调用 `unwrap_or_else` 时就已经确定了。 所以,当你想要在 `Err` 时使用固定的默认值时,就可以使用 `unwrap_or`;而当你想要在 `Err` 时使用可变的值时,就可以使用 `unwrap_or_else`。 示例代码: ```rust let x: Result<i32, &str> = Err("error message"); // 使用 unwrap_or 返回默认值 let y = x.unwrap_or(0); // 使用 unwrap_or_else 返回闭包的结果 let z = x.unwrap_or_else(|| { println!("error message: {}", x.unwrap_err()); 0 }); ``` ### 回答2: 在Rust,`unwrap_or`和`unwrap_or_else`都是处理Option类型的方法,用于在Option为None时提供一个默认值。它们之间的区别在于如何传递默认值。 对于`unwrap_or`,默认值是通过传递一个具体的值作为参数来提供的。例如,如果有一个Option类型的变量`value`,可以使用`value.unwrap_or(0)`来检查`value`的值。如果`value`是Some,则返回`value`的值;如果`value`是None,则返回传递的默认值0。 对于`unwrap_or_else`,默认值是通过传递一个闭包(函数指针)来提供的。闭包将在Option为None时被调用,并返回默认值。例如,如果有一个Option类型的变量`value`,可以使用`value.unwrap_or_else(|| 0)`来检查`value`的值。如果`value`是Some,则返回`value`的值;如果`value`是None,则调用闭包`|| 0`,返回0作为默认值。 `unwrap_or`和`unwrap_or_else`的选择取决于默认值的类型和计算成本。如果默认值是一个简单的固定值,更适合使用`unwrap_or`方法。如果默认值的计算可能比较昂贵,或者需要依赖外部状态,更适合使用`unwrap_or_else`方法,因为它提供了一种延迟计算、按需提供默认值的方式。 总之,`unwrap_or`和`unwrap_or_else`都提供了处理Option类型的方法,在Option为None时提供默认值。它们之间的区别在于如何传递默认值,`unwrap_or`传递具体值,`unwrap_or_else`传递闭包函数。 ### 回答3: `unwrap_or` 和 `unwrap_or_else` 都是 Rust Option 类型的方法,用于处理可能为 None 的值。它们的区别在于它们处理 None 值的方式。 `unwrap_or` 方法接受一个参数,表示当 Option 值是 None 时要返回的备用值。如果 Option 值是 Some,则直接返回其的值;如果 Option 值是 None,则返回提供的备用值。 举个例子,假设有一个 Option 值为 Some(10),我们可以使用 `unwrap_or` 来获取其的值,如果 Option 值是 None,则返回一个备用值,比如 0。代码如下: ```rust let value = Some(10); let result = value.unwrap_or(0); println!("{}", result); // 输出 10 ``` 另一方面,`unwrap_or_else` 方法接受一个闭包作为参数,当 Option 值是 None 时会调用该闭包来生成一个备用值。如果 Option 值是 Some,则直接返回其的值。 举个例子,假设有一个 Option 值为 None,我们可以使用 `unwrap_or_else` 来生成一个备用值,比如通过闭包计算出来。代码如下: ```rust let value: Option<i32> = None; let result = value.unwrap_or_else(|| 2 + 3); println!("{}", result); // 输出 5 ``` 总的来说,使用 `unwrap_or` 可以提供一个默认的备用值,而使用 `unwrap_or_else` 可以动态生成一个备用值。因此,选择使用哪个方法取决于我们对于备用值的需求和计算方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值