[英]How can I pattern match against an Option<String>?
I can straight-forwardly match a String
in Rust:我可以直接匹配 Rust 中的
String
:
let a = "hello".to_string();
match &a[..] {
"hello" => {
println!("Matches hello");
}
_ => panic!(),
}
If I have an option type, it fails:如果我有一个选项类型,它会失败:
match Some(a) {
Some("hello") => {
println!("Matches some hello");
}
_ => panic!(),
}
because the types don't match:因为类型不匹配:
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`
I can't do the [..]
trick because we have an Option
.我不能做
[..]
把戏,因为我们有一个Option
。 The best that I have come up with so far is:到目前为止,我想出的最好的是:
match Some(a) {
Some(b) => match (&b[..]) {
"hello" => {
println!("Matches some, some hello");
}
_ => panic!(),
},
None => panic!(),
}
which works but is terrible for its verbosity.这有效,但因其冗长而可怕。
In this case, my code is just an example.在这种情况下,我的代码只是一个例子。 I do not control the creation of either the
String
or the Some(String)
— so I can't change this type in reality as I could do in my example.我不控制
String
或Some(String)
——所以我不能像在我的例子中那样在现实中改变这种类型。
Any other options?还有其他选择吗?
It's a known limitation of Rust's patterns.这是 Rust 模式的一个已知限制。
Method calls (including internal methods for operators like ==
) automatically call .deref()
as needed, so String
gets automagically turned into &str
for comparisons with literals.方法调用(包括
==
运算符的内部方法.deref()
根据需要自动调用.deref()
,因此String
会自动转换为&str
以与文字进行比较。
On the other hand, the patterns are quite literal in their comparisons, and find that String
and &str
are different.另一方面,模式在它们的比较中非常直接,并且发现
String
和&str
是不同的。
There are two solutions:有两种解决方案:
Change Option<String>
to Option<&str>
before matching on it: Some(a).as_deref()
.在匹配之前将
Option<String>
更改为Option<&str>
: Some(a).as_deref()
。 The as_deref()
is a combo of as_ref()
that makes Option<&String>
(preventing move), and deref()
/ as_str()
then unambiguously references it as a &str
.所述
as_deref()
是一个组合as_ref()
使Option<&String>
(防止移动),和deref()
/ as_str()
然后明确地引用它作为一个&str
。
Use match guard: match Some(a) { Some(ref s) if s == "hello" => … }
.使用匹配保护:
match Some(a) { Some(ref s) if s == "hello" => … }
。 Some(ref s)
matches any String
, and captures it as s: &String
, which you can then compare in the if
guard which does the usual flexible coercions to make it work. Some(ref s)
匹配任何String
,并将其捕获为s: &String
,然后您可以在if
守卫中进行比较,该守卫执行通常的灵活强制以使其工作。
See also:另见:
As of Rust 1.40, you can now call as_deref
on Option<String>
to convert it to Option<&str>
and then match on it:从 Rust 1.40 开始,您现在可以在
Option<String>
上调用as_deref
将其转换为Option<&str>
,然后对其进行匹配:
match args.nth(1).as_deref() {
Some("help") => {}
Some(s) => {}
None => {}
}
I found this because it is one of the clippy lints .我发现了这个,因为它是一种可剪的 lints 。
Look at this . 看看这个。
You cannot match on std::String
, as you've found, only on &str
.正如您所发现的,您无法在
std::String
上匹配,只能在&str
上匹配。 Nested pattern matches work, so if you can match on &str
, you can match on Option<&str>
, but still not on Option<String>
.嵌套模式匹配有效,因此如果您可以匹配
&str
,则可以匹配Option<&str>
,但仍然不能匹配Option<String>
。
In the working example, you turned the std::String
into a &str
by doing &a[..]
.在工作示例中,您通过执行
&a[..]
将std::String
转换为&str
。 If you want to match on a Option<String>
, you have to do the same thing.如果你想匹配
Option<String>
,你必须做同样的事情。
One way is to use nested matches:一种方法是使用嵌套匹配:
match a {
Some(ref s) => match &s[..] {
"hello" => /* ... */,
_ => /* ... */,
},
_ => /* ... */,
}
But then you have to duplicate the "otherwise" code if it's the same, and it's generally not as nice.但是,如果“其他”代码相同,则必须复制“其他”代码,并且通常没有那么好。
Instead, you can turn the Option<String>
into an Option<&str>
and match on this, using the map
function.相反,您可以使用
map
函数将Option<String>
转换为Option<&str>
并对其进行匹配。 However, map
consumes the value it is called on, moving it into the mapping function.然而,
map
消耗了它被调用的值,将它移动到映射函数中。 This is a problem because you want to reference the string, and you can't do that if you have moved it into the mapping function.这是一个问题,因为您想要引用字符串,如果您将它移到映射函数中,则不能这样做。 You first need to turn the
Option<String>
into a Option<&String>
and map on that.您首先需要将
Option<String>
转换为Option<&String>
并对其进行映射。
Thus you end up with a.as_ref().map(|s| /* s is type &String */ &s[..])
.因此你最终得到
a.as_ref().map(|s| /* s is type &String */ &s[..])
。 You can then match on that.然后你可以匹配它。
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"),
}
In some cases, you can use unwrap_or
to replace Option::None
with a predefined &str
you don't want to handle in any special way.在某些情况下,您可以使用
unwrap_or
将Option::None
替换为您不想以任何特殊方式处理的预定义&str
。
I used this to handle user inputs:我用它来处理用户输入:
let args: Vec<String> = env::args().collect();
match args.get(1).unwrap_or(&format!("_")).as_str() {
"new" => {
print!("new");
}
_ => {
print!("unknown string");
}
};
Or to match your code:或匹配您的代码:
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.