【问题标题】:How can I pull data out of an Option for independent use?如何从选项中提取数据以供独立使用?
【发布时间】:2021-03-07 20:27:53
【问题描述】:

有没有办法从Option 中“提取”数据?我有一个返回 Some(HashMap) 的 API 调用。我想使用HashMap,就好像它不在Some 中一样,并使用数据。

根据我的阅读,Some(...) 似乎只适用于匹配比较和一些内置函数。

从 crate 文档中提取的简单 API 调用:

use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp = reqwest::blocking::get("https://httpbin.org/ip")?
        .json::<HashMap<String, String>>()?;
    println!("{:#?}", resp.get("origin"));
    Ok(())
}

结果:

Some("75.69.138.107")

【问题讨论】:

    标签: rust enums pattern-matching optional


    【解决方案1】:

    最常用的方式是if let

    if let Some(origin) = resp.get("origin") {
        origin.do_stuff()
    }
    

    对于更细粒度的控制,可以使用模式匹配:

    match resp.get("origin") {
        Some(origin) => origin.do_stuff(),
        None => panic!("origin not found!")
    }
    

    您也可以使用unwrap,这将为您提供期权的基础价值,或者panic,如果它是None

    let origin = resp.get("origin").unwrap();
    

    您可以使用expect 自定义panic 消息:

    let origin = resp.get("origin").expect("Oops!");
    

    或者用unwrap_or计算一个默认值:

    let origin = resp.get("origin").unwrap_or(&String::from("192.168.0.1"));
    

    你也可以返回错误而不是恐慌:

    let origin = resp.get("origin").ok_or(Error::UnknownOrigin)?;
    

    【讨论】:

      【解决方案2】:

      你的选择很多。

      if let Some(origin) = resp.get("origin") {
          // do stuff using origin
      }
      
      origin = resp.get("origin").unwrap()
      // will panic if None
      
      resp.get("origin").map(|origin| {
          // do stuff using inner value, returning another option
      })
      
      resp.get("origin").and_then(|origin| {
          // same as map but short-circuits if there is no inner value
      })
      

      【讨论】:

      • mapand_then “短路”如果值为 Noneand_then 只是 map(...).flatten() 的简写,如果函子本身返回 Option
      • @kmdreko 有点奇怪,文档为and_then 指定了这种行为,但没有为map 提及它
      • OTOH,如果它短路,你希望它做什么?如果没有给 origin 参数的值,它就不能调用闭包......
      【解决方案3】:
      if let Some(origin) = resp.get("origin") {
          // use origin
      }
      

      如果你能保证值不可能是None,那么你可以使用:

      let origin = resp.get("origin").unwrap();
      

      或者:

      let origin = resp.get("origin").expect("This shouldn't be possible!");
      

      而且,由于您的函数返回Result

      let origin = resp.get("origin").ok_or("This shouldn't be possible!")?;
      

      或者带有自定义错误类型:

      let origin = resp.get("origin").ok_or(MyError::DoesntExist)?;
      

      【讨论】:

        猜你喜欢
        • 2016-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-15
        • 1970-01-01
        相关资源
        最近更新 更多