验证枚举与 vec 中关联值的唯一性

J. *_*Doe 1 rust

下面的代码中我定义了一个输入类型为 的方法Vec<Food>。此方法应该在不检查关联值的情况下验证手臂是否必须是唯一的。这意味着它最多应包含 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

SCa*_*lla 5

要比较enum变体而不关心任何关联数据,该函数std::mem::discriminant非常有用。给定一个enum类型的值,std::mem::discriminant返回一个类型的值std::mem::Discriminant,该值告诉该值是哪个变体。std::mem::DiscriminantImplements Hash,因此我们可以将迄今为止看到的所有变体保留在 a 中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(())
}
Run Code Online (Sandbox Code Playgroud)

(操场)