Rust模式匹配增强库try_match的使用,提供更简洁安全的Option和Result解包方案
// 基本用法示例
use try_match::{try_match, match_ok, match_or_default, unwrap_match};
#[derive(Copy, Clone, Debug, PartialEq)]
enum Enum { Var0, Var1(i32), Var2(i32, i32) }
use Enum::*;
// `try_match!` 返回 `Result`:成功时为 `Ok(bindings)`,否则为 `Err(input_value)`
assert_eq!(try_match!(Var1(42), Var1(x)), Ok(42));
assert_eq!(try_match!(Var0, Var1(x)), Err(Var0));
// `match_ok!` 返回 `Option`
assert_eq!(match_ok!(Var1(42), Var1(x)), Some(42));
assert_eq!(match_ok!(Var0, Var1(x)), None);
// `match_or_default!` 在失败时返回默认值
assert_eq!(match_or_default!(Var1(42), Var1(x)), 42);
assert_eq!(match_or_default!(Var0, Var1(x)), 0);
// `unwrap_match!` 在失败时 panic:
assert_eq!(unwrap_match!(Var1(42), Var1(x)), 42);
// unwrap_match!(Var0, Var1(x)); // 这会 panic
// 支持匹配守卫(`if <expr>`):
assert_eq!(match_ok!(Var1(42), Var1(x)), Some(42));
assert_eq!(match_ok!(Var1(42), Var1(x) if x < 20), None);
// 绑定示例
// 如果没有绑定变量,返回 `()`(由 `Ok(_)` 包装)
assert_eq!(unwrap_match!(Var1(42), Var1(_)), ());
// ... 如果恰好有一个绑定,返回绑定的值
assert_eq!(unwrap_match!(Var1(42), Var1(x)), 42);
// ... 如果有多个绑定,返回一个匿名结构体
let vars = unwrap_match!(Var2(12, 34), Var2(a, b));
assert_eq!((vars.a, vars.b), (12, 34));
// ... 如果绑定名称是数字,返回一个元组
let (a, b) = unwrap_match!(Var2(12, 34), Var2(_0, _1));
assert_eq!((a, b), (12, 34));
// 可选的 `=>` 子句指定显式映射
assert_eq!(unwrap_match!(Var1(42), Var1(x) => x + 1), 43);
assert_eq!(unwrap_match!(Var0, Var0 => "yay"), "yay");
// 部分应用示例
// 省略 scrutinee 表达式以生成闭包
let _: Option<i32> = match_ok!(Var1(42), Var1(x));
let _: fn(Enum) -> Option<i32> = match_ok!( , Var1(x));
// 应用示例:Iterator::filter_map
let array = [Var1(42), Var0, Var1(10)];
let filtered: Vec<_> = array
.iter()
.filter_map(match_ok!(, &Var1(_0) if _0 > 20))
.collect();
assert_eq!(filtered, [42]);
// 应用示例:Iterator::map + Fallible Iterator::collect
let array = [Var1(42), Var0, Var1(10)];
let filtered: Result<Vec<_>, _> = array
.iter()
.map(try_match!(, &Var1(_0) if _0 > 20))
.collect();
// `Var0` 是第一个不匹配的值
assert_eq!(filtered, Err(&Var0));
// 应用示例:提取变体
impl Enum {
fn var1(&self) -> Option<&i32> {
match_ok!(self, Var1(_0))
}
fn is_var2(&self) -> bool {
matches!(self, Var0)
}
}
let enums = [Var1(42), Var0];
assert_eq!(enums[0].var1(), Some(&42));
assert_eq!(enums[1].var1(), None);
assert!(!enums[0].is_var2());
assert!(enums[1].is_var2());
// 应用示例:期望特定变体
fn this_fn_expects_var2(foo: &Enum) {
let i = unwrap_match!(foo, &Var2(42, _0));
// 或者,你可以使用 let-else(在 Rust 1.65.0 中稳定):
// let &Var2(42, i) = foo else { panic!("{foo:?}") };
assert_eq!(i, 84);
}
this_fn_expects_var2(&Var2(42, 84));
// 相关作品比较
let success1 = matches!(Some(42), Some(_));
let success2 = match_ok!(Some(42), Some(_)).is_some();
assert_eq!(success1, success2);
完整示例demo:
// 完整 try_match 库使用示例
use try_match::{try_match, match_ok, match_or_default, unwrap_match};
// 定义示例枚举
#[derive(Copy, Clone, Debug, PartialEq)]
enum MyEnum {
UnitVariant,
SingleValue(i32),
TupleValue(i32, i32),
StructValue { x: i32, y: i32 },
}
use MyEnum::*;
fn main() {
// 1. try_match! 宏示例 - 返回 Result
println!("=== try_match! 示例 ===");
let result1 = try_match!(SingleValue(42), SingleValue(x));
println!("try_match SingleValue(42): {:?}", result1); // Ok(42)
let result2 = try_match!(UnitVariant, SingleValue(x));
println!("try_match UnitVariant: {:?}", result2); // Err(UnitVariant)
// 2. match_ok! 宏示例 - 返回 Option
println!("\n=== match_ok! 示例 ===");
let option1 = match_ok!(SingleValue(42), SingleValue(x));
println!("match_ok SingleValue(42): {:?}", option1); // Some(42)
let option2 = match_ok!(UnitVariant, SingleValue(x));
println!("match_ok UnitVariant: {:?}", option2); // None
// 3. match_or_default! 宏示例
println!("\n=== match_or_default! 示例 ===");
let value1 = match_or_default!(SingleValue(42), SingleValue(x));
println!("match_or_default SingleValue(42): {}", value1); // 42
let value2 = match_or_default!(UnitVariant, SingleValue(x));
println!("match_or_default UnitVariant: {}", value2); // 0
// 4. unwrap_match! 宏示例
println!("\n=== unwrap_match! 示例 ===");
let unwrapped = unwrap_match!(SingleValue(42), SingleValue(x));
println!("unwrap_match SingleValue(42): {}", unwrapped); // 42
// unwrap_match!(UnitVariant, SingleValue(x)); // 这会 panic
// 5. 匹配守卫示例
println!("\n=== 匹配守卫示例 ===");
let guarded = match_ok!(SingleValue(42), SingleValue(x) if x > 30);
println!("匹配守卫 x > 30: {:?}", guarded); // Some(42)
let guarded_fail = match_ok!(SingleValue(15), SingleValue(x) if x > 30);
println!("匹配守卫 x > 30 (失败): {:?}", guarded_fail); // None
// 6. 多绑定示例
println!("\n=== 多绑定示例 ===");
let multi = unwrap_match!(TupleValue(10, 20), TupleValue(a, b));
println!("多绑定匿名结构体: a={}, b={}", multi.a, multi.b);
let tuple_bind = unwrap_match!(TupleValue(10, 20), TupleValue(_0, _1));
println!("数字绑定元组: ({}, {})", tuple_bind.0, tuple_bind.1);
// 7. => 映射子句示例
println!("\n=== => 映射子句示例 ===");
let mapped = unwrap_match!(SingleValue(5), SingleValue(x) => x * 2);
println!("映射 x * 2: {}", mapped); // 10
let unit_mapped = unwrap_match!(UnitVariant, UnitVariant => "success");
println!("UnitVariant 映射: {}", unit_mapped); // "success"
// 8. 部分应用示例
println!("\n=== 部分应用示例 ===");
let matcher: fn(MyEnum) -> Option<i32> = match_ok!(, SingleValue(_0));
let partial_result = matcher(SingleValue(100));
println!("部分应用结果: {:?}", partial_result); // Some(100)
// 9. 迭代器应用示例
println!("\n=== 迭代器应用示例 ===");
let items = [SingleValue(42), UnitVariant, SingleValue(30), SingleValue(15)];
// filter_map 应用
let filtered: Vec<i32> = items
.iter()
.filter_map(match_ok!(, &SingleValue(x) if x > 20))
.collect();
println!("filter_map 结果: {:?}", filtered); // [42, 30]
// try_match 收集
let collected: Result<Vec<i32>, _> = items
.iter()
.map(try_match!(, &SingleValue(x)))
.collect();
println!("try_match 收集: {:?}", collected); // Err(&UnitVariant)
}
// 为枚举实现便捷方法
impl MyEnum {
fn get_single_value(&self) -> Option<&i32> {
match_ok!(self, SingleValue(_0))
}
fn is_unit_variant(&self) -> bool {
matches!(self, UnitVariant)
}
}
// 测试函数
#[test]
fn test_enum_methods() {
let enums = [SingleValue(42), UnitVariant];
assert_eq!(enums[0].get_single_value(), Some(&42));
assert_eq!(enums[1].get_single_value(), None);
assert!(!enums[0].is_unit_variant());
assert!(enums[1].is_unit_variant());
}
// 期望特定变体的函数
fn expect_tuple_variant(value: &MyEnum) -> i32 {
let result = unwrap_match!(value, &TupleValue(10, second));
result.second
}
#[test]
fn test_expect_variant() {
let value = TupleValue(10, 50);
assert_eq!(expect_tuple_variant(&value), 50);
}
1 回复
try_match:Rust模式匹配增强库
介绍
try_match是一个Rust库,旨在为Option和Result类型提供更简洁、安全的解包方案。它通过扩展模式匹配功能,减少了样板代码的使用,同时保持了Rust的安全性和表达能力。
主要特性
- 简化Option和Result的解包操作
- 提供更清晰的错误处理流程
- 减少嵌套的match表达式
- 保持编译时安全性
安装方法
在Cargo.toml中添加依赖:
[dependencies]
try_match = "0.1.0"
使用方法
基本Option解包
use try_match::try_match;
fn process_data(input: Option<i32>) -> Option<String> {
let value = try_match!(Some(x) = input)?;
Some(format!("Processed: {}", value))
}
Result类型处理
use try_match::try_match;
fn handle_result(input: Result<i32, String>) -> Result<String, String> {
let value = try_match!(Ok(x) = input).map_err(|_| "Invalid value".to_string())?;
Ok(format!("Success: {}", value))
}
带条件的模式匹配
use try_match::try_match;
fn process_with_condition(input: Option<i32>) -> Option<String> {
let value = try_match!(Some(x) if x > 0 = input)?;
Some(format!("Positive value: {}", value))
}
嵌套模式匹配
use try_match::try_match;
fn handle_nested(input: Option<Result<i32, String>>) -> Result<String, String> {
let inner_result = try_match!(Some(x) = input).ok_or("No value".to_string())?;
let value = try_match!(Ok(y) = inner_result)?;
Ok(format!("Final value: {}", value))
}
错误处理示例
use try_match::try_match;
fn safe_division(a: i32, b: i32) -> Result<f64, String> {
let divisor = try_match!(Some(d) if d != 0 = Some(b))
.ok_or("Division by zero".to_string())?;
Ok(a as f64 / divisor as f64)
}
完整示例demo
// 引入try_match库
use try_match::try_match;
fn main() {
// 示例1: 基本Option解包
let result1 = process_data(Some(42));
println!("示例1结果: {:?}", result1); // 输出: Some("Processed: 42")
// 示例2: Result类型处理
let result2 = handle_result(Ok(100));
println!("示例2结果: {:?}", result2); // 输出: Ok("Success: 100")
// 示例3: 带条件的模式匹配
let result3 = process_with_condition(Some(5));
println!("示例3结果: {:?}", result3); // 输出: Some("Positive value: 5")
// 示例4: 嵌套模式匹配
let nested_input = Some(Ok(200));
let result4 = handle_nested(nested_input);
println!("示例4结果: {:?}", result4); // 输出: Ok("Final value: 200")
// 示例5: 错误处理
let division_result = safe_division(10, 2);
println!("示例5结果: {:?}", division_result); // 输出: Ok(5.0)
let division_error = safe_division(10, 0);
println!("示例5错误: {:?}", division_error); // 输出: Err("Division by zero")
}
// 基本Option解包函数
fn process_data(input: Option<i32>) -> Option<String> {
// 使用try_match解包Some值,如果为None则直接返回None
let value = try_match!(Some(x) = input)?;
Some(format!("Processed: {}", value))
}
// Result类型处理函数
fn handle_result(input: Result<i32, String>) -> Result<String, String> {
// 解包Ok值,如果为Err则映射错误信息
let value = try_match!(Ok(x) = input).map_err(|_| "Invalid value".to_string())?;
Ok(format!("Success: {}", value))
}
// 带条件的模式匹配函数
fn process_with_condition(input: Option<i32>) -> Option<String> {
// 解包Some值并检查条件x > 0
let value = try_match!(Some(x) if x > 0 = input)?;
Some(format!("Positive value: {}", value))
}
// 嵌套模式匹配函数
fn handle_nested(input: Option<Result<i32, String>>) -> Result<String, String> {
// 先解包外层的Some
let inner_result = try_match!(Some(x) = input).ok_or("No value".to_string())?;
// 再解包内层的Ok
let value = try_match!(Ok(y) = inner_result)?;
Ok(format!("Final value: {}", value))
}
// 安全除法函数
fn safe_division(a: i32, b: i32) -> Result<f64, String> {
// 检查除数不为零
let divisor = try_match!(Some(d) if d != 0 = Some(b))
.ok_or("Division by zero".to_string())?;
Ok(a as f64 / divisor as f64)
}
优势
- 代码更简洁:减少match表达式的嵌套层级
- 可读性更强:直观的模式匹配语法
- 安全性保持:编译时类型检查不变
- 错误处理灵活:与?操作符完美配合
注意事项
- 需要Rust 1.56或更高版本
- 在某些复杂场景下,传统的match表达式可能更合适
- 建议在团队项目中统一使用规范
这个库特别适合需要大量处理Option和Result类型的项目,能显著提升代码的简洁性和可维护性。