在 vec 中使用关联值验证枚举的唯一性



下面是一些代码,其中我定义了一个输入类型为Vec<Food>的方法。此方法应验证 arm 是否必须唯一,而不检查关联的值。这意味着它最多应该包含 1 个比萨饼、1 个蛋糕和 1 个地铁。注意:不需要所有手臂都在Vec.我也在下面的代码中写了一些测试,它们仍然需要通过。

我的"真实"代码中有更多的枚举臂,而且我目前的方式不能很好地扩展,所以我希望有一种更简单的方法。

fn main() {
}
enum Food {
Cake(String),
Pizza(i32),
Subway(u64)
}
struct CustomError;
fn validate(foods: Vec<Food>) -> Result<(), CustomError> {
let mut cake = false;
let mut pizza = false;
let mut subway = false;
for f in foods.iter() {
match f {
Food::Cake(_) => {
if cake {
return Err(CustomError)
}
cake = true;
},
Food::Pizza(_) => {
if pizza {
return Err(CustomError)
}
pizza = true;
},
Food::Subway(_) => {
if subway {
return Err(CustomError)
}
subway = true;
},
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
assert!(validate(vec![Food::Pizza(1)]).is_ok());
assert!(validate(vec![Food::Pizza(1), Food::Cake("Apple".to_owned())]).is_ok());
assert!(validate(vec![]).is_ok());
assert!(validate(vec![Food::Pizza(1), Food::Pizza(1)]).is_err());
assert!(validate(vec![Food::Pizza(1), Food::Pizza(2)]).is_err());
}
}

要在不关心任何关联数据的情况下比较enum变体,函数std::mem::discriminant非常有用。给定一个enum类型的值,std::mem::discriminant返回一个类型为std::mem::Discriminant的值,该值告知该值是哪个变体。std::mem::Discriminant实现了Hash,因此我们可以将到目前为止看到的所有变体保留在一个HashSet中,以检查是否有任何重复项。

只是一个小技巧:HashSet::insert返回一个布尔值,当插入的元素尚未在集合中时,该布尔值为 true。这意味着我们可以结合检查是否看到判别式和插入新判别式的步骤。

use std::collections::HashSet;
use std::mem::discriminant;
enum Food {
Cake(String),
Pizza(i32),
Subway(u64),
}
struct CustomError;
fn validate(foods: Vec<Food>) -> Result<(), CustomError> {
let mut discriminants = HashSet::new();
for food in foods {
if !discriminants.insert(discriminant(&food)) {
return Err(CustomError);
}
}
Ok(())
}

(游乐场(

Rust 没有太多的反射功能,所以我怀疑你能做的最好的事情就是编写一个类似过程宏的东西来生成一个包含你描述的 match 语句的函数不想手写。

最新更新