如何强制匹配的返回类型为()?

Ric*_*ter 5 rust

在下面的简化示例中,编译器抱怨match语句的一个分支返回bool,而另一个分支返回()

use std::collections::{HashMap, HashSet};

fn main() {
    let available = HashMap::from_iter([(2, "b"), (3, "c"), (4, "d")]);
    let mut set = HashSet::new();
    
    for i in [1, 2, 3, 4, 5] {
        match available.get(&i) {
            Some(s) => set.insert(*s),
            None => ()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但这会导致错误:

error[E0308]: `match` arms have incompatible types
  --> src/main.rs:10:21
   |
8  | /         match available.get(&i) {
9  | |             Some(s) => set.insert(*s),
   | |                        -------------- this is found to be of type `bool`
10 | |             None => ()
   | |                     ^^ expected `bool`, found `()`
11 | |         }
   | |_________- `match` arms have incompatible types
Run Code Online (Sandbox Code Playgroud)

如何通知编译器 match 语句应该 return (),并且bool返回的 frominsert应该被忽略?

Mas*_*inn 12

通常的方法是将手臂放在一个块中并用 来覆盖它;,因为这会抑制表达式的结果:

use std::collections::{HashMap, HashSet};

fn main() {
    let available = HashMap::from_iter([(2, "b"), (3, "c"), (4, "d")]);
    let mut set = HashSet::new();
    
    for i in [1, 2, 3, 4, 5] {
        match available.get(&i) {
            Some(s) => {
                set.insert(*s);
            }
            None => (),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一个可能不太常见的替代方案是将值提供给函数,将其“转换”为()例如drop

use std::collections::{HashMap, HashSet};

fn main() {
    let available = HashMap::from_iter([(2, "b"), (3, "c"), (4, "d")]);
    let mut set = HashSet::new();
    
    for i in [1, 2, 3, 4, 5] {
        match available.get(&i) {
            Some(s) => drop(set.insert(*s)),
            None => (),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以完全忽略第二个分支:

use std::collections::{HashMap, HashSet};

fn main() {
    let available = HashMap::from_iter([(2, "b"), (3, "c"), (4, "d")]);
    let mut set = HashSet::new();
    
    for i in [1, 2, 3, 4, 5] {
        if let Some(s) = available.get(&i) {
            set.insert(*s);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者使用高阶函数来解决这种副作用,虽然这不是最常见的:

use std::collections::{HashMap, HashSet};

fn main() {
    let available = HashMap::from_iter([(2, "b"), (3, "c"), (4, "d")]);
    let mut set = HashSet::new();
    
    for i in [1, 2, 3, 4, 5] {
        available.get(&i).map(|&s| set.insert(s));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 总共只有 2 个变体,“if let”可能是最简洁的编写方式。 (2认同)

Joh*_*ica 5

您可以将这两个块都转换为语句:

match available.get(&i) {
    Some(s) => {
        set.insert(*s);
    }
    None => {}
}
Run Code Online (Sandbox Code Playgroud)

或者您可以将 转换matchif- let

if let Some(&s) = available.get(&i) {
    set.insert(s);
}
Run Code Online (Sandbox Code Playgroud)

  • 在“None”分支中将“()”变成“{}”有什么意义?它不会改变任何东西。 (2认同)