Rust每周一库: matches!

每周一个 rust 库的时间到了,今天要介绍的是matches库。

最近Patrick Walton分析了crates.io上的500个rust库,对这些库按照某个维度计算了分数进行排名,其中一个分数就是根据它的流行度和它的大小计算一个分数进行排名,用来挑选小而美的rust库,这些库可以移植到标准库中,或者可以汇总到一个大库中。这个指数叫做left-pad index, 这个排名文件可以在这里找到。

left-pad是2016年nodejs圈发生的一个非常著名的事件。left-pad是一个只有17行的npm代码库,却被很多的代码库所使用,包括 babel 这样的热门项目。作者 Azer 将其从npm删除后,所有直接或者间接依赖这个模块的 NPM 包就悲剧的挂掉了,影响广泛。 原因在于作者写了一个叫 kik 的工具和某个公司同名了,这天公司的律师要求其删掉这个模块,把 kik 这个名字“让”给他们,作者不答应,律师就直接找 NPM 了,而 NPM 未经作者同意就把包的权限转移给了这家公司。于是,Azer 一怒冲冠,将他所有的 NPM 包全部删掉了。

所以Patrick Walton分析了crates.io库,对于那些代码量很小但是全被广泛应用的库提出了讨论,这些库是不是应该移动到标准库中?

其中,排名第一的就是matches库。

matches是一个宏,可以用来评估一个表达式是否和模式匹配,它返回一个布尔类型的值。

比如:

1
2
3
4
5
#[macro_use] extern crate matches;
fn is_slash(input: &str, pos: uint) -> bool {
matches!(input.char_at(pos), '/' | '\\')
}

又比如:

1
2
3
4
5
6
7
#[macro_use] extern crate matches;
extern crate serialize;
use serialize::json::Json;
fn object_has_key(json: &Json, key: &str) -> bool {
matches!(json, &Json::Object(ref obj) if obj.contains_key(key))
}

事实上,它是将rust模式匹配的一种特例,通过一个宏,简单的写一行代码实现一个模式匹配的结果。

所以它的实现也很简单,也是我们学习宏的一个很好的范例:

1
2
3
4
5
6
7
8
9
#[macro_export]
macro_rules! matches {
($expression:expr, $($pattern:tt)+) => {
match $expression {
$($pattern)+ => true,
_ => false
}
}
}

你可以直接使用模式匹配实现你的功能,但是你需要写至少三行代码,通过这个宏,你只需简单的调用即可,可以很方便的用在表达式的计算之中。

它还提供了两个额外的宏assert_matches!debug_assert_matches,用来进行assert匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#[macro_export]
macro_rules! assert_matches {
($expression:expr, $($pattern:tt)+) => {
match $expression {
$($pattern)+ => (),
ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
}
}
}
#[macro_export]
macro_rules! debug_assert_matches {
($expression:expr, $($pattern:tt)+) => {
if cfg!(debug_assertions) {
match $expression {
$($pattern)+ => (),
ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
}
}
}
}

有一个issue记录了将这个功能移植到标准库的提案,遗憾的设计这个提案居然没有被采纳,不管怎样,根据left-pad指数,这个库还是得到了大家的喜爱并被广泛应用。

crates.io现在对包的管理也有问题。比如match,看起来就像域名贩卖系统一样,公开出让这个库名,又比如google,没有任何代码,只是一种对google的批判。

后续,我会继续介绍几个小而美的rust库。