5 个版本 (3 个破坏性更新)
0.4.0 | 2023 年 10 月 4 日 |
---|---|
0.3.1 | 2023 年 10 月 4 日 |
0.3.0 | 2023 年 10 月 4 日 |
0.2.0 | 2023 年 10 月 3 日 |
0.1.0 | 2023 年 10 月 2 日 |
#916 在 Rust 模式
每月 26 次下载
17KB
78 行
rustcomp
为 Rust 添加惯用推导。这是通过一个函数宏 rcomp!
实现的,该宏展开为迭代器。
以下内容修改自 文档
基本用法
核心思想很简单:提供一个简单且简洁的方式来扁平化、过滤、映射和收集迭代器。有关语法的完整分解,请参阅 rcomp!
宏的文档。现在,考虑以下简单示例
let v = rcomp![Vec<_>; for x in 0..10 => x];
let it = (0..10).collect::<Vec<_>>(); // all examples show an equivalent iterator
这将创建一个包含数字 0 到 9 的 Vec<i32>
的向量...不是很实用,对吧?让我们添加一个守卫来过滤掉奇数
let v = rcomp![Vec<_>; for x in 0..10 => x, if x % 2 == 0];
let it = (0..10).filter(|x| x % 2 == 0).collect::<Vec<_>>();
现在我们有点进展了!您还可以映射值,所以让我们将它们加倍以供娱乐
let v = rcomp![Vec<_>; for x in 0..10 => x * 2, if x % 2 == 0];
let it = (0..10)
.filter(|x| x % 2 == 0)
.map(|x| x * 2)
.collect::<Vec<_>>();
注意,在迭代器示例中,map
调用是在 filter
调用之后。这正是推导的工作方式:守卫应用于 输入 值,而不是输出值。
说到迭代器,如果您不想将结果收集到容器中,可以直接通过省略收集类型来获取迭代器
// now we have to collect the iterator ourselves
let v = rcomp![for x in 0..10 => x].collect::<Vec<_>>();
// equivalent to:
let vv = rcomp![Vec<_>; for x in 0..10 => x];
解构
推导也支持解构。例如,元组
let pairs = vec![(1, 2), (3, 4), (5, 6)];
let v = rcomp![Vec<_>; for (x, y) in &pairs => x + y];
let it = pairs.into_iter().map(|(x, y)| x + y).collect::<Vec<_>>();
或结构体
struct Point {
x: i32,
y: i32,
}
let points = vec![Point::new(1, 2), Point::new(3, 4), Point::new(5, 6)];
let v = rcomp![Vec<_>; for Point { x, y } in &points => x + y];
let it = points.into_iter().map(|Point { x, y }| x + y).collect::<Vec<_>>();
扁平化
通过链式连接 for-in
子句,支持递归限制内的嵌套迭代器的扁平化。
let matrix = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
let v = rcomp![Vec<_>; for row in &matrix, col in row => *col * 2, if *col % 2 == 0];
// nested loops are a much nicer example than iterators here
let mut it = Vec::new();
for row in &matrix {
for col in row {
if *col % 2 == 0 {
it.push(*col * 2);
}
}
}
高级示例
有关创建 HashMap
或 HashSet
等的高级示例,请参阅 rcomp!
宏的文档。
迭代器示例说明
需要注意的是,用于测试推导的迭代器示例与推导是 等效的,但 不是相同的。宏展开为嵌套的 flat_map
和 filter_map
调用链;示例是为了清晰度和显示推导中的操作顺序而编写的。例如,早期的矩阵示例展开为
let v = (&matrix)
.into_iter()
.flat_map(|row| {
row.into_iter().filter_map(|col| {
if (*col % 2 == 0) && true {
Some((*col * 2))
} else {
None
}
})
})
.collect::<Vec<_>>();
注意展开中使用了 into_iter
。
那么 mapcomp
呢?
我知道存在mapcomp
crate,但它在几个方面与这个crate有所不同。首先,mapcomp
旨在使其语法尽可能接近Python,我认为他们做得很好;这个crate并不试图这样做。这个crate的目标是以一种符合Rust语法的自然方式向Rust添加列表推导,同时保持其简洁和强大。此外,mapcomp
提供了多个宏来支持不同类型的列表推导,而此crate只提供了一个。
在更技术性的层面上,mapcomp
内部使用生成器,这在Rust 2018版本中是可以的,但现在生成器和yield
都是实验性特性。这为此crate提供了很大的启发,因为我想要创建一个基于宏的解决方案,不需要nightly版本,所以我选择了迭代器而不是生成器。