1 个不稳定版本
0.1.5 | 2023年12月16日 |
---|
#85 in #newtype
92KB
1K SLoC
identified_vec
这是一个独特的可识别元素集合,它保留了插入顺序,灵感来源于 Pointfree的Swift Identified Collections。
与标准 Vec
类似,IdentifiedVec
按照特定用户指定的顺序维护其元素。然而,与 Vec
不同,IdentifiedVec
引入了唯一标识元素的能力,使用哈希表确保没有两个元素具有相同的标识符,并有效地查找与特定标识符对应的元素。
IdentifiedVec
当您需要能够通过稳定的标识符高效访问唯一元素时,是 Vec
的有用替代品。它也是 BTreeSet
的有用替代品,其中 Ord
特性要求可能过于严格,是 HashSet
的有用替代品,其中 Hash
特性要求可能过于严格。
您可以使用实现 Identifiable
特性的任何元素类型来创建一个已识别的向量。
示例
extern crate identified_vec;
use identified_vec::{IsIdentifiableVec, IdentifiedVec, Identifiable, IdentifiedVecOf};
use std::cell::RefCell;
#[derive(Eq, PartialEq, Clone, Debug)]
struct User {
id: &'static str,
name: RefCell<&'static str>,
}
impl User {
fn new(id: &'static str, name: &'static str) -> Self {
Self {
id,
name: RefCell::new(name),
}
}
fn name(&self) -> &'static str {
*self.name.borrow()
}
}
Identifiable
impl Identifiable for User {
type ID = &'static str;
fn id(&self) -> Self::ID {
self.id
}
}
from_iter
let mut users = IdentifiedVecOf::<User>::from_iter([
User::new("u_42", "Satoshi Nakamoto"),
User::new("u_1337", "Leia Skywalker"),
]);
assert_eq!(
users.get(&"u_42").map(|u| u.name()),
Some("Satoshi Nakamoto")
);
assert_eq!(
users.get_at_index(1).map(|u| u.name()),
Some("Leia Skywalker")
);
append
& elements()
users.append(User::new("u_237", "Alan Turing"));
assert_eq!(
users.elements(),
[
User::new("u_42", "Satoshi Nakamoto"),
User::new("u_1337", "Leia Skywalker"),
User::new("u_237", "Alan Turing"),
]
.iter()
.collect::<Vec<&User>>()
);
// Element with same ID is not appended:
users.append(User::new("u_42", "Tom Mervolo Dolder"));
assert_eq!(
users.elements(),
[
User::new("u_42", "Satoshi Nakamoto"),
User::new("u_1337", "Leia Skywalker"),
User::new("u_237", "Alan Turing"),
]
.iter()
.collect::<Vec<&User>>()
);
update_or_insert
// Element with same ID replaces existing if an `update_*` method is used:
// e.g. `update_or_insert`:
users.update_or_insert(User::new("u_42", "Tom Mervolo Dolder"), 0);
assert_eq!(
users.elements(),
[
User::new("u_42", "Tom Mervolo Dolder"),
User::new("u_1337", "Leia Skywalker"),
User::new("u_237", "Alan Turing"),
]
.iter()
.collect::<Vec<&User>>()
);
update_or_append
// or `update_or_append`
users.update_or_append(User::new("u_237", "Marie Curie"));
assert_eq!(
users.elements(),
[
User::new("u_42", "Tom Mervolo Dolder"),
User::new("u_1337", "Leia Skywalker"),
User::new("u_237", "Marie Curie"),
]
.iter()
.collect::<Vec<&User>>()
);
或者,您可以提供一个闭包来描述元素的标识符
let numbers = IdentifiedVec::<u32, u32>::new_identifying_element(|e| *e);
动机
标准集合中没有任何一个(BTreeSet
和 HashSet
)保留了插入顺序,Vec
保留了插入顺序,但它允许有重复项。因此,如果您想有一个保留插入顺序的唯一元素集合(类似Set),则 IdentifiedVec
满足您的需求。甚至更好,元素不需要实现 Hash
或 Ord
。
标志
此crate具有以下Cargo功能
serde
:在IdentifiedVecOf
类型上启用serde序列化支持(其中Element
实现Identifiable
特性)。id_prim
:为原始类型获取Identifiable
特质的实现:i8
,...,i128
,u8
,...,u128
和bool
(不是很实用,只允许在IdentifiedVecOf
中有元素,但谁又在乎这些呢。)
实现细节
一个已标识的向量由一个保持插入顺序的 Vec
的 ID
和一个 HashMap
的 id-元素对组成,以便在给定 ID 的情况下以恒定时间查找元素。
许可证
在 MIT 许可证下授权(LICENSE-MIT 或 https://open-source.org.cn/licenses/MIT)
依赖
约 300–770KB
约 18K SLoC