繁体   English   中英

如何对选项进行模式匹配<String> ?

[英]How can I pattern match against an Option<String>?

我可以直接匹配 Rust 中的String

let a = "hello".to_string();

match &a[..] {
    "hello" => {
        println!("Matches hello");
    }
    _ => panic!(),
}

如果我有一个选项类型,它会失败:

match Some(a) {
    Some("hello") => {
        println!("Matches some hello");
    }
    _ => panic!(),
}

因为类型不匹配:

error[E0308]: mismatched types
 --> src/main.rs:5:14
  |
5 |         Some("hello") => {
  |              ^^^^^^^ expected struct `std::string::String`, found reference
  |
  = note: expected type `std::string::String`
             found type `&'static str`

我不能做[..]把戏,因为我们有一个Option 到目前为止,我想出的最好的是:

match Some(a) {
    Some(b) => match (&b[..]) {
        "hello" => {
            println!("Matches some, some hello");
        }
        _ => panic!(),
    },
    None => panic!(),
}

这有效,但因其冗长而可怕。

在这种情况下,我的代码只是一个例子。 我不控制StringSome(String) ——所以我不能像在我的例子中那样在现实中改变这种类型。

还有其他选择吗?

这是 Rust 模式的一个已知限制。

方法调用(包括==运算符的内部方法.deref()根据需要自动调用.deref() ,因此String会自动转换为&str以与文字进行比较。

另一方面,模式在它们的比较中非常直接,并且发现String&str是不同的。

有两种解决方案:

  1. 在匹配之前将Option<String>更改为Option<&str>Some(a).as_deref() 所述as_deref()是一个组合as_ref()使Option<&String> (防止移动),和deref() / as_str()然后明确地引用它作为一个&str

  2. 使用匹配保护: match Some(a) { Some(ref s) if s == "hello" => … } Some(ref s)匹配任何String ,并将其捕获为s: &String ,然后您可以在if守卫中进行比较,该守卫执行通常的灵活强制以使其工作。

另见:

从 Rust 1.40 开始,您现在可以在Option<String>上调用as_deref将其转换为Option<&str> ,然后对其进行匹配:

match args.nth(1).as_deref() {
    Some("help") => {}
    Some(s) => {}
    None => {}
}

我发现了这个,因为它是一种可剪的 lints

看看这个

正如您所发现的,您无法在std::String上匹配,只能在&str上匹配。 嵌套模式匹配有效,因此如果您可以匹配&str ,则可以匹配Option<&str> ,但仍然不能匹配Option<String>

在工作示例中,您通过执行&a[..]std::String转换为&str 如果你想匹配Option<String> ,你必须做同样的事情。

一种方法是使用嵌套匹配:

match a {
    Some(ref s) => match &s[..] {
        "hello" => /* ... */,
        _ => /* ... */,
    },
    _ => /* ... */,
}

但是,如果“其他”代码相同,则必须复制“其他”代码,并且通常没有那么好。

相反,您可以使用map函数将Option<String>转换为Option<&str>并对其进行匹配。 然而, map消耗了它被调用的值,将它移动到映射函数中。 这是一个问题,因为您想要引用字符串,如果您将它移到映射函数中,则不能这样做。 您首先需要将Option<String>转换为Option<&String>并对其进行映射。

因此你最终得到a.as_ref().map(|s| /* s is type &String */ &s[..]) 然后你可以匹配它。

match os.as_ref().map(|s| &s[..]) {
    Some("hello") => println!("It's 'hello'"),
    // Leave out this branch if you want to treat other strings and None the same.
    Some(_) => println!("It's some other string"),
    _ => println!("It's nothing"),
}

在某些情况下,您可以使用unwrap_orOption::None替换为您不想以任何特殊方式处理的预定义&str

我用它来处理用户输入:

let args: Vec<String> = env::args().collect();

match args.get(1).unwrap_or(&format!("_")).as_str() {
    "new" => {
        print!("new");
    }
    _ => {
        print!("unknown string");
    }
};

或匹配您的代码:

let option = Some("hello");

match option.unwrap_or(&format!("unhandled string").as_str()) {
    "hello" => {
        println!("hello");
    }
    _ => {
        println!("unknown string");
    }
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM