1 个不稳定版本
0.1.0 | 2022 年 11 月 24 日 |
---|
#60 在 #defines
9KB
定义另一种类型的 match
语句。
与将单个值与多个模式进行比较不同,fn_match
将每个值传递给一个给定的函数,并根据哪个情况导致有利的结果来评估表达式。
与传统的 match
可以像一系列 if x == y
为各种 y
行为一样,fn_match
可以像(并展开为)一系列 if let Some(x) = foo(bar)
为各种 bar
。
示例
快速入门
let x = fn_match! {
with fn: foo => y;
"bar" => baz(y),
"baz" => bar(y)
};
展开为
let x = if let Some(y) = foo("bar") {
Some(baz(y))
} else if let Some(y) = foo("baz") {
Some(bar(y))
} else {
None
};
详细示例
一个用例(也是主要用例)是当使用具有互斥捕获组的 Regex
时。
let regex = Regex::new(r#"^(?:(?P<int>\d+)|(?P<str>".+")|(?P<flt>\d+\.\d+))$"#).unwrap();
#
#
#
此正则表达式可以捕获一个整型字面量(235
)、一个字符串字面量("hello"
)或一个(无符号)浮点字面量(87.43
),并可用于生成以下枚举的实例
enum Token {
Int(u64),
Str(String),
Float(f64)
}
在标准 Rust 中,从给定的 &str
生成 Token
的代码可能如下所示
let input = r#""hello world""#;
let caps = regex.captures(input).expect("failed to match");
let token = if let Some(tok) = caps.name("int").map(|s| s.as_str()) {
Token::Int(tok.parse().unwrap())
} else if let Some(tok) = caps.name("str").map(|s| s.as_str()) {
Token::Str(tok.trim_matches('\"').to_string())
} else if let Some(tok) = caps.name("flt").map(|s| s.as_str()) {
Token::Float(tok.parse().unwrap())
} else { panic!("failed to match") };
assert_eq!(token, Token::Str(String::from("hello world")));
应用 fn_match
以及额外的闭包,可以减少重复,并将代码重写为以下内容
let input = r#"42"#;
let caps = regex.captures(input).expect("failed to match");
let f = |g| caps.name(g).map(|s| s.as_str());
let token = fn_match! {
with fn: f => tok;
"int" => Token::Int(tok.parse().unwrap()),
"str" => Token::Str(tok.trim_matches('\"').to_string()),
"flt" => Token::Float(tok.parse().unwrap())
}.expect("failed to match");
assert_eq!(token, Token::Int(42));
fn_match 语法
fn_match
块有三个主要部分
- 要调用的函数
- 一个标识符
- 一系列的左右表达式对
#
with fn: f => tok;
#
此行提供了一个函数和一个标识符。该函数(位于 fn:
和 =>
之间)需要接受一个类型,该类型是后续行提供的单个值,并返回一个 Option
。
注意:函数表达式放置在每个if let
尝试之后进行展开。如果函数是闭包,建议在fn_match
之前将其存储在变量中,以防止在最终代码中写入多个相同的闭包。
标识符(在=>
和;
之间)用于引用包含的Some
值,如果函数返回该值。(它用作if let Some(x)
)的绑定模式。
在此行之后是一系列匹配对。
#
"int" => Token::Int(tok.parse().unwrap()),
#
=>
的左侧是测试值,需要传递到之前提供的函数中。
右侧是一个要评估/返回的表达式(在它自己的Some
中包装),如果函数使用左侧值调用时返回Some
。右侧也可以引用标识符作为相关的Some
值。
整个fn_match
块表达式评估为Option
。要么是一个包含左侧匹配的右侧的Some
,要么是如果没有左侧匹配,则返回None
。