我想将值与常量或其他值进行比较。在另一种语言(例如JavaScript)中我会这样做:
// Pretend these are values that are generated another way
let a = 23;
let b = 16;
let c = 43;
let input = 23;
switch (input) {
case a: console.log("Input is equal to a"); break;
case b: console.log("Input is equal to b"); break;
case c: console.log("Input is equal to c"); break;
default: console.log("Input does not equal any value"); break;
}
我怎样才能在Rust中整齐地做到这一点?我知道我可以用if语句来做,但我认为这很麻烦,而且我正在与更多的值进行比较。
我可以使用match语句将Rust中的变量与常量值进行比较吗?
进行此类案例分析的最简单方法是事先知道案例的值,并且不介意将它们放在代码中间。在这种情况下,一个简单的match
表达式就是你想要的。
fn main() {
for &input in &[16, 23, 42, 43] {
match input {
23 => println!("Input is equal to a"),
16 => println!("Input is equal to b"),
43 => println!("Input is equal to c"),
_ => println!("Input does not equal any value"),
}
}
}
如果你的a
b
和c
是编译时常量(已知值或用const
函数生成),那么你仍然可以直接匹配它们。
const A: i32 = 23;
const B: i32 = 16;
const C: i32 = generate_c();
const fn generate_c() -> i32 {
A + B + 4
}
fn main() {
for &input in &[16, 23, 42, 43] {
match input {
A => println!("Input is equal to a"),
B => println!("Input is equal to b"),
C => println!("Input is equal to c"),
_ => println!("Input does not equal any value"),
}
}
}
但是,如果您使用非常量变量进行尝试,则会得到奇怪的输出。
fn generate_c(a: i32, b: i32) -> i32 {
a + b + 4
}
fn main() {
let a = 23;
let b = 16;
let c = generate_c(a, b);
for &input in &[16, 23, 42, 43] {
match input {
a => println!("Input is equal to a"),
b => println!("Input is equal to b"),
c => println!("Input is equal to c"),
_ => println!("Input does not equal any value"),
}
}
}
如果你运行它,编译器会给你很多关于“无法访问的模式”的警告,输出将是“输入等于一个”四次。这个问题是匹配语句中每一行的左侧不仅仅是一个表达式,而是一个模式。
模式是像(x, [_, z], Some(_))
这样的表达。它是由基本变量(如x
和z
),下划线(_
),所有文字表达式(整数,浮点数,元组,数组)和其他一些东西构建的。
当Rust运行这样的匹配语句时,它会尝试在语法上将输入与模式匹配。基本变量将匹配任何内容,并且该变量的值设置为匹配match语句的该分支范围的任何值。下划线(在所有上述示例中使用)也匹配任何内容,但不绑定任何变量。
使用上面的const
版本,常量A
B
和C
将替换为代码中各处的各自的字面值,因此输入在这些文字值上匹配。
对于变量版本,当我们与a
b
和c
匹配时,这些字母被解释为匹配任何东西的基本变量。模式中根本不考虑变量的值。在代码中
let a = 14;
let b = 15;
let c = 16;
let input = 16;
match input {
a => println!("Input is equal to a"),
b => println!("Input is equal to b"),
c => println!("Input is equal to c"),
_ => println!("Input does not equal any value"),
}
第一个分支将始终匹配,为输入提供分支范围的名称a
。
如果你需要匹配变量a
b
和c
,你可以为每个分支添加一个守卫。保护通过为要匹配的分支添加附加条件来过滤分支。在这种情况下,我们匹配任何东西并将其绑定到变量x
,但然后检查x
是否等于a
(和b
和c
)。
fn generate_c(a: i32, b: i32) -> i32 {
a + b + 4
}
fn main() {
let a = 23;
let b = 16;
let c = generate_c(a, b);
for &input in &[16, 23, 42, 43] {
match input {
x if x == a => println!("Input is equal to a"),
x if x == b => println!("Input is equal to b"),
x if x == c => println!("Input is equal to c"),
_ => println!("Input does not equal any value"),
}
}
}
这比开关/外壳结构稍微冗长一点,但我希望很明显发生了什么。在每个分支处,变量x绑定到16,然后如果它等于变量A
(或B
或C
),则采用该分支。否则,我们尝试下一个分支。