16次发布
使用旧的Rust 2015
0.5.2 | 2023年6月4日 |
---|---|
0.5.1 | 2021年4月11日 |
0.5.0 | 2018年12月26日 |
0.3.4 | 2018年3月22日 |
0.1.1 | 2015年11月27日 |
在Rust模式中排名443
每月下载量515
用于 4 crate
30KB
348 行
guard
这个特性已经正式加入到Rust中。当#![feature(let_else)]
稳定后,这个crate应该被视为过时。
此crate导出了一个宏,实现了RFC 3137(最初为RFC 1303)的大部分功能,这是一种类似于Swift中的“let-else”或“guard”表达式。
RFC中确定的语法是let PAT = EXPR else { BODY }
(其中BODY
必须发散)。此宏理解并实现了编译器中已实现的多数功能,同时也有一些在第一个RFC中提出的变体,即在中间的else
子句。
该crate还实现了一个名为guard_unwrap
的变体,如果匹配失败则引发恐慌。
示例
#[macro_use] extern crate guard;
use std::env;
fn main() {
// read configuration from a certain environment variable
// do nothing if the variable is missing
guard!(let Ok(foo) = env::var("FOO") else { return });
println!("FOO = {}", foo);
}
Cargo功能
nightly
在历史上是必需的,用于在夜间编译器编译时避免警告。现在它不再执行任何操作,仅保留以支持向后兼容。debug
启用trace_macros
以进行调试。需要夜间编译器(但不需此crate的nightly
功能)。
工作原理
将这种行为实现为宏很困难,因为必须在封装作用域中创建一个 let
语句。除此之外,还希望避免重复模式绑定标识符的需要。这里使用的策略是扫描模式以查找标识符,并使用该标识符构建一个顶层的 let
语句,该语句内部使用 match
来应用模式。这种扫描几乎总是可能的——请参见下文中的限制 #1 和 #2。
这种策略还意味着 PAT
需要以未解析的标记树序列的形式输入到宏中。有两种方法可以接受无界的标记树序列作为输入而不引起歧义错误:将标记树放在末尾(我的当前选择)或将它们放在括号中。最初,这个选择导致了反向调用语法。从版本 0.2.0 开始,通过采用两次解析策略,支持更方便的语法:宏基本上将其整个输入视为标记序列,在 =
和 else
处分割,然后再次解析结果。
在展开过程中存在许多细微之处,以避免各种警告和陷阱;有关更多详细信息,请参阅宏源代码。
限制
- 模式中的表达式不支持。这是当前 Rust 宏系统的一个限制——我想说“在这个位置解析一个标识符,如果失败则尝试解析一个表达式”,但这是不可能的;我只能测试 特定 的标识符。可以通过使用模式守卫(如
match
)来轻松绕过这个限制。 - 空的、无命名空间的枚举变体和结构体会导致展开失败,因为宏认为它们是标识符。尽管如此,也可以绕过这个限制,尽管有一个公开的 PR 旨在移除最简单的解决方案
PAT
不能被推翻。这与if let
和match
的行为相同,而且无论如何编写一个带有不可推翻模式的守卫也是无用的(你只需要使用let
),所以这不应该是一个问题。由于限制#1,这可能会比本来更令人烦恼。尽管如此,如果#14252得到修复,可以通过在展开中插入一个空操作模式守卫来允许不可推翻的模式。
与rustc实现的差异
- 不需要在或模式周围使用括号
- 不能将
ref
绑定到非可复制的值(你会得到一个borrowck错误)