6个版本
0.2.0 | 2020年4月12日 |
---|---|
0.1.5 | 2016年8月20日 |
0.1.3 | 2016年4月11日 |
0.1.2 | 2016年2月29日 |
0.1.0 | 2015年12月7日 |
#991 在 进程宏 中
8KB
64 行
Try-Let
这是一个类似于在RFC #1303中提出的try-let实现的进程宏。
注意: 语句位置的进程宏目前是不稳定的,这意味着在PR #68717 合并之前,此宏在稳定版Rust上不会工作。
有关更多详细信息,请参阅文档。
lib.rs
:
这是一个类似于在RFC #1303中提出的try-let实现的进程宏。
注意: 语句位置的进程宏目前是不稳定的,这意味着在PR #68717 合并之前,此宏在稳定版Rust上不会工作。
用法
try-let是通过进程宏实现的,因为像try-let需要的那样解析模式表达式,使用macro_rules!
宏是不可能的。
此插件目前需要启用#![feature(proc_macro_hygiene)]
,如下所示
#![feature(proc_macro_hygiene)]
use try_let::try_let;
实际使用与let
表达式非常相似
try_let!(Some(x) = foo else {
return Err("Shoot! There was a problem!")
});
else之后的表达式必须发散(例如,通过return
、continue
、break
或panic!
)。
这也可以处理比Some
和None
更复杂的类型
enum E {
A(i32, i32, i32, i32, Option<i32>, Result<(), i32>),
B,
}
let foo = E::A(0, 21, 10, 34, Some(5), Err(32));
try_let!(E::A(a, 21, c, 34, Some(e), Err(f)) = foo else {
unreachable!()
});
// a, c, e, and f are all bound here.
assert_eq!(a, 0);
assert_eq!(c, 10);
assert_eq!(e, 5);
assert_eq!(f, 32);
为什么
这提供了一个简单的方法来避免在Rust中进行大量失效模式匹配的逻辑向右移动。这允许主逻辑流程继续而无需增加缩进级别,同时用发散逻辑处理错误。
如何
一个try_let!()
调用展开为以下内容
try_let!(Some(x) = foo else {
return Err("Shoot! There was a problem!");
});
// ... becomes ...
let (x,) = match foo {
Some(x) => (x,),
_ => {
return Err("Shoot! There was a problem!");
}
};
关于None
和空枚举变体的说明
现在有些人可能会问的一个问题是,像 None 这样的枚举变体是如何处理的?
try_let!(None = foo else {
return;
});
// ... becomes ...
let () = match foo {
None => (),
_ => {
return;
}
};
None 并不会被 try-let 误认为是绑定变量,因为 try-let 用来工作的一个不大不小的技巧是:它依赖于 Rust 的风格约定。解析器(语法扩展所能访问的所有内容)无法确定模式中的单独标识符是一个像
None 这样的空枚举变体,还是一个像
x 这样的变量绑定。这个决定是在编译器中稍后进行的,对于这个扩展来说太晚了,无法使用这个信息。
相反,扩展会检查标识符的第一个字符。如果它是一个 ASCII 大写字母,我们就假设它是一个空枚举变体;否则,我们假设它是一个变量绑定。
依赖关系
~1.5MB
~35K SLoC