12 个版本
0.4.0 | 2024年7月3日 |
---|---|
0.3.4 | 2023年3月28日 |
0.3.3 | 2022年12月30日 |
0.3.2 | 2022年6月19日 |
0.1.0 | 2021年4月13日 |
#819 在 Rust 模式
54 每月下载次数
31KB
663 行
Ordes
一个将数组(arrays)和元组(tuples)处理得更像向量的crate。
目前,此crate提供了通过 .pop()
、.rest()
、.push(val)
和 .cons(val)
方法通过 OrdesPop
、OrdesRest
、OrdesPush
和 OrdesCons
traits 分别实现,并额外提供了通过 .split()
、.concat(arr)
、.remove()
和 .insert(val)
方法通过 OrdesSplit
、OrdesConcat
、OrdesRemove
和 OrdesInsert
traits 分别实现的通过 const_generics
crate 功能,这需要一个 nightly 编译器和启用了不完整的 generic_const_exprs
功能。这四个 trait 只是通过这个功能提供和实现的,因为每个单独的一个都需要非线性扩展的 trait 实现数量,而且我不确定有人愿意忍受那些编译时间。同样,它们也只适用于数组。
这个crate的诞生源于我固执地想要在可能的情况下使用迭代器而不是 for
循环,这使得数据打包有时变得有些痛苦。例如,考虑一个生成所有小写四字母“单词”的迭代器。
('a'..='z')
.flat_map(|l1| ('a'..='z').map(move |l2| (l1, l2)))
.flat_map(|(l1, l2)| ('a'..='z').map(move |l3| (l1, l2, l3)))
.flat_map(|(l1, l2, l3)| ('a'..='z').map(move |l4| (l1, l2, l3, l4)))
.for_each(|(l1, l2, l3, l4)| println!("{}{}{}{}", l1, l2, l3, l4));
如我们所见,这既是
- 并不特别令人愉快地编写或查看
- 一个理智的人不会做的事情
这个crate提供了一个替代方案
use ordes::OrdesPush;
('a'..='z')
.flat_map(|l1| ('a'..='z').map(move |l2| (l1, l2)))
.flat_map(|chars| ('a'..='z').map(move |l3| chars.push(l3)))
.flat_map(|chars| ('a'..='z').map(move |l4| chars.push(l4)))
.for_each(|(l1, l2, l3, l4)| println!("{}{}{}{}", l1, l2, l3, l4));
这里并没有发生真正的魔法。代码.push(val)
生成一个新类型的数据。在第一个例子中,代码chars.push(l3)
,输入类型是(char, char)
,输出是(char, char, char)
。对于代码chars.push(l4)
也是类似的——输入类型为(char, char, char)
,输出为(char, char, char, char)
。使用数组也可以实现几乎相同的实现。
use ordes::OrdesPush;
('a'..='z')
.flat_map(|l1| ('a'..='z').map(move |l2| [l1, l2]))
.flat_map(|chars| ('a'..='z').map(move |l3| chars.push(l3)))
.flat_map(|chars| ('a'..='z').map(move |l4| chars.push(l4)))
.for_each(|[l1, l2, l3, l4]| println!("{}{}{}{}", l1, l2, l3, l4));
在这种情况下,代码chars.push(l3)
接收[char; 2]
并生成[char; 3]
,而代码chars.push(l4)
接收[char; 3]
并生成[char; 4]
。
最近出现的一个愚蠢的用例让我添加了两个新的特性——《OrdesRest》和《OrdesCons
use std::net::IpAddr;
use ordes::OrdesCons;
fn ipaddr_bytestream(addr: IpAddr) -> impl Iterator<Item = u8> {
let mut data = [0; 17];
let len = match addr {
IpAddr::V4(addr) => {
data[0..5].copy_from_slice(&addr.octets().cons(4));
5
},
IpAddr::V6(addr) => {
data[0..17].copy_from_slice(&addr.octets().cons(6));
17
}
};
data.into_iter().take(len)
}
如果没有.cons(_)
,在每个分支中都需要再添加一行代码来将4
或6
写入到data[0]
中。这是一个小小的改进,但我还是觉得很有价值。
在这个包中,我为数组实现了《OrdesPop`,《OrdesRest`,《OrdesPush
- 在稳定版中,所有特性仅针对长度最多为32的数组实现(默认情况下,有最多支持到1024的功能)。
- 在夜间版和稳定版中,所有特性仅针对最多32种类型的元组实现(默认情况下,有最多支持到1024的功能)。
此crate暴露的所有特性方法都消耗self
并产生一个更长或更短的类型(在元组的情况下,可能还会添加或删除最后一个类型)。我非常清楚这是一个非常有限的使用场景,但对我很有用,也许对其他一些人也有用。
关于const_generics
功能的说明
为了使用此crate的const_generics
功能,您还必须在crate中某处放置以下代码(例如lib.rs
、main.rs
等):#![feature(generic_const_exprs)]
。如果未启用此功能,则依赖于ConstCheck<B>
的此crate中的任何特性实现都将失败。
依赖项
~1.5MB
~36K SLoC