[英]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!(),
}
这有效,但因其冗长而可怕。
在这种情况下,我的代码只是一个例子。 我不控制String
或Some(String)
——所以我不能像在我的例子中那样在现实中改变这种类型。
还有其他选择吗?
这是 Rust 模式的一个已知限制。
方法调用(包括==
运算符的内部方法.deref()
根据需要自动调用.deref()
,因此String
会自动转换为&str
以与文字进行比较。
另一方面,模式在它们的比较中非常直接,并且发现String
和&str
是不同的。
有两种解决方案:
在匹配之前将Option<String>
更改为Option<&str>
: Some(a).as_deref()
。 所述as_deref()
是一个组合as_ref()
使Option<&String>
(防止移动),和deref()
/ as_str()
然后明确地引用它作为一个&str
。
使用匹配保护: 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_or
将Option::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.