我有这个枚举:
enum MyEnum {
Var1,
Var2(u32),
Var3(u32, u32),
}
Run Code Online (Sandbox Code Playgroud)
我想实现以下行为:
let mut set = HashSet::new();
set.insert(MyEnum::Var1);
set.insert(MyEnum::Var1);
set.insert(MyEnum::Var2(1));
set.insert(MyEnum::Var2(2));
set.insert(MyEnum::Var3(1, 1));
set.insert(MyEnum::Var3(1, 1));
set.insert(MyEnum::Var3(2, 1));
set.insert(MyEnum::Var3(2, 2));
println!("set = {:?}", set);
// set = {Var1, Var2(1), Var2(2), Var3(1, 1), Var3(2, 1)}
Run Code Online (Sandbox Code Playgroud)
也就是说,我想专门Hash
更改变体的行为,使其仅依赖于它的第一个。Var3
u32
重要的是,我不想详尽地介绍match
每个枚举变体,因为我想保留所有其他枚举变体的默认行为。因此,据我所知,这些 答案不足以满足我的需求。
我想出的解决方案是这样的:
#[derive(Debug, Eq)]
enum MyEnum {
Var1,
Var2(u32),
Var3(u32, u32),
}
impl PartialEq for MyEnum {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(MyEnum::Var3(a, _), MyEnum::Var3(b, _)) => a == b,
_ => format!("{:?}", self) == format!("{:?}", other),
}
}
}
impl Hash for MyEnum {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
MyEnum::Var3(a, _) => a.hash(state),
_ => format!("{:?}", self).hash(state)
}
}
}
Run Code Online (Sandbox Code Playgroud)
...我正在寻找反馈/更好的解决方案。
kmd*_*eko 10
衍生包的构建是为了提供标准特征的自动实现,并支持常见的自定义。有了这个箱子,你就可以得到你想要的东西,如下所示:
use std::collections::HashSet;
use derivative::Derivative; // 2.2.0
#[derive(Debug, Eq, Derivative)]
#[derivative(PartialEq, Hash)]
enum MyEnum {
Var1,
Var2(u32),
Var3(
u32,
#[derivative(PartialEq="ignore")]
#[derivative(Hash="ignore")]
u32
),
}
fn main() {
let mut set = HashSet::new();
set.insert(MyEnum::Var1);
set.insert(MyEnum::Var1);
set.insert(MyEnum::Var2(1));
set.insert(MyEnum::Var2(2));
set.insert(MyEnum::Var3(1, 1));
set.insert(MyEnum::Var3(1, 1));
set.insert(MyEnum::Var3(2, 1));
set.insert(MyEnum::Var3(2, 2));
println!("set = {:?}", set);
}
Run Code Online (Sandbox Code Playgroud)
use std::collections::HashSet;
use derivative::Derivative; // 2.2.0
#[derive(Debug, Eq, Derivative)]
#[derivative(PartialEq, Hash)]
enum MyEnum {
Var1,
Var2(u32),
Var3(
u32,
#[derivative(PartialEq="ignore")]
#[derivative(Hash="ignore")]
u32
),
}
fn main() {
let mut set = HashSet::new();
set.insert(MyEnum::Var1);
set.insert(MyEnum::Var1);
set.insert(MyEnum::Var2(1));
set.insert(MyEnum::Var2(2));
set.insert(MyEnum::Var3(1, 1));
set.insert(MyEnum::Var3(1, 1));
set.insert(MyEnum::Var3(2, 1));
set.insert(MyEnum::Var3(2, 2));
println!("set = {:?}", set);
}
Run Code Online (Sandbox Code Playgroud)
在操场上看到它。
@kmdreko 的答案展示了如何使用第三方板条箱来实现该Hash
特征。在大多数情况下,这将是首选方式,因为它需要更少的代码,并且您不必手动确保Hash
不违反Eq
合同。
为了完整起见,您可以在没有第三方包的情况下手动实现它:
impl Hash for MyEnum {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
MyEnum::Var1 => {
state.write_u8(1); // use any distinct number as an enum variant identifier
}
MyEnum::Var2(v) => {
state.write_u8(2); // use any distinct number as an enum variant identifier
v.hash(state); // hash the actual value
}
MyEnum::Var3(v, _) => {
state.write_u8(3);
v.hash(state);
}
}
}
}
impl PartialEq for MyEnum {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(MyEnum::Var1, MyEnum::Var1) => true,
(MyEnum::Var2(x), MyEnum::Var2(y)) => x == y,
(MyEnum::Var3(x, _), MyEnum::Var3(y, _)) => x == y,
_ => false,
}
}
}
impl Eq for MyEnum {}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3623 次 |
最近记录: |