用?内封闭

问题描述 投票:1回答:1

我有这个简单的解析功能

use std::collections::BTreeMap;

fn parse_kv(data: &str) -> BTreeMap<String, String> {
    data.split('&')
        .map(|kv| kv.split('='))
        .map(|mut kv| (kv.next().unwrap().into(), kv.next().unwrap().into()))
        .collect()
}

#[test]
fn parse_kv_test() {
    let result = parse_kv("test1=1&test2=2");
    assert_eq!(result["test1"], "1");
    assert_eq!(result["test2"], "2");
}

它工作正常,但我希望有Option或Result返回类型,如下所示:

fn parse_kv(data: &str) -> Option<BTreeMap<String, String>>

这个实现:

fn parse_kv(data: &str) -> Option<BTreeMap<String, String>> {
    Some(data.split('&')
        .map(|kv| kv.split('='))
        .map(|mut kv| (kv.next()?.into(), kv.next()?.into()))
        .collect())
}

不幸的是给出了以下错误:

error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
  --> src/ecb_cut_paste.rs:23:24
   |
23 |         .map(|mut kv| (kv.next()?.into(), kv.next()?.into()))
   |                        ^^^^^^^^^^ cannot use the `?` operator in a function that returns `(_, _)`
   |
   = help: the trait `std::ops::Try` is not implemented for `(_, _)`
   = note: required by `std::ops::Try::from_error`

是否有可能在闭包中使用?运算符从这样的函数返回None?如果没有,我将如何处理这种情况呢?

rust
1个回答
5
投票

这里的问题是闭包本身是一个函数,所以使用?将从闭包而不是外部函数返回。这仍然可以用来实现你想要的功能,但是:

use std::collections::BTreeMap;

fn parse_kv(data: &str) -> Option<BTreeMap<String, String>> {
    data.split('&')
        .map(|kv| kv.split('='))
        .map(|mut kv| Some((kv.next()?.into(), kv.next()?.into())))
        .collect()
}

#[test]
fn parse_kv_test() {
    let result = parse_kv("test1=1&test2=2").unwrap();
    assert_eq!(result["test1"], "1");
    assert_eq!(result["test2"], "2");

    let result2 = parse_kv("test1=1&test2");
    assert_eq!(result2, None);
}

这里有几点要注意:首先,第二个Some(...)调用中的问号和map意味着你有一个Option<(String, String)>的迭代器 - 类型推断为你找出这个。

下一点需要注意的是,collect()可以自动将Iterator<Option<T>>转换为Option<Collection<T>>(与Result相同 - relevant documentation here)。我添加了一个测试,证明这是有效的。

另外需要注意的是,以这种方式使用collect仍然可以实现短路。一旦第一个None由迭代器产生,collect将立即返回None,而不是继续处理每个元素。

© www.soinside.com 2019 - 2024. All rights reserved.