Rust 中 opt.map_or(Ok(None), |r| r.map(Some)) 里 Some 是什么用法?

描述

一般说来 Some 都是带有一个关联值的枚举类型;这里: opt.map_or(Ok(None), |r| r.map(Some)) some 是什么用法?

use std::num::ParseIntError;


fn double_first(vec: Vec<&str>) -> Result<Option<i32>, ParseIntError> {
     // vec.first():返回类型Option<&str>
     // option<&str>.map(|first|) : first是 &str
     //first.parse::<i32>(): 类型 result<i32,ParseIntError>
     //Result<i32,ParseIntError>.map(|n|): n是i32, 返回值类型 Result<i32,ParseIntError>
    let opt = vec.first().map(|first| {
        first.parse::<i32>().map(|n| 2 * n)
    });
    
    //opt:Option<Result<i32,ParseIntError>>
    //opt.map_or(): pub fn map_or<U, F>(self, default: U, f: F) -> U where F: FnOnce(T) -> U, 
    opt.map_or(Ok(None), |r| r.map(Some))  //这里返回什么类型?r| r.map(Some) 中的Some是什么意思?
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    println!("The first doubled is {:?}", double_first(numbers));
    println!("The first doubled is {:?}", double_first(empty));
    println!("The first doubled is {:?}", double_first(strings));
}

期望

有理有据,尽量给出参考链接.

阅读 3.8k
3 个回答

opt.map_or(Ok(None), |r| r.map(Some))

这里的 rResult<i32, ParseIntError> 类型的

map

pub fn map<U, F>(self, op: F) -> Result<U, E>
where
    F: FnOnce(T) -> U,

Resultmap 要的是一个 FnOnce 的 trait

Function item types

When referred to, a function item, or the constructor of a tuple-like struct or enum variant, yields a zero-sized value of its function item type.

......

All function items implement Fn, FnMut, FnOnce, Copy, Clone, Send, and Sync.

enume variant (比如 Some)实现了 FnOnce 的 trait。

所以 Some 可以用于 mapop 参数。

opt.map_or(Ok(None), |r| r.map(Some))
应该等价于

opt.map_or(Ok(None), |r| r.map(|a| Some(a)))

返回的就是函数签名里的Result<Option<i32>, ParseIntError>,Some用于直接构造一个值为Some<i32>(a)的Option

发现 The Book 中也给出了相关的解释, 里面的解释更容易理解。

The name of each enum variant that we define also becomes an initializer function. We can use these initializer functions as function pointers that implement the closure traits, which means we can specify the initializer functions as arguments for methods that take closures, like so:
    enum Status {
        Value(u32),
        Stop,
    }

    let list_of_statuses: Vec<Status> = (0u32..20).map(Status::Value).collect();

Here we create Status::Value instances using each u32 value in the range that map is called on by using the initializer function of Status::Value. Some people prefer this style, and some people prefer to use closures. They compile to the same code, so use whichever style is clearer to you.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进