簡體   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