[英]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.