代码之家  ›  专栏  ›  技术社区  ›  Philipp Ludwig

如果我不关心枚举的字段,如何断言它是特定变量?

  •  2
  • Philipp Ludwig  · 技术社区  · 7 年前

    我想在测试中用字段检查枚举,而现在忽略字段的实际值。

    请考虑以下示例:

    enum MyEnum {
        WithoutFields,
        WithFields { field: String },
    }
    
    fn return_with_fields() -> MyEnum {
        MyEnum::WithFields {
            field: "some string".into(),
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn example() {
            assert_eq!(return_with_fields(), MyEnum::WithFields {..});
        }
    }
    

    playground

    我想用 assert_eq! 这里,但是编译器告诉我:

    error: expected expression, found `}`
      --> src/lib.rs:18:64
       |
    18 |         assert_eq!(return_with_fields(), MyEnum::WithFields {..});
       |                                                                ^ expected expression
    

    这和 Why do I get an error when pattern matching a struct-like enum variant with fields? 但是这个解决方案不适用于我的情况。

    当然,我可以用 match 我自己做,但能用 断言“EQ! 会减少工作量。

    2 回复  |  直到 7 年前
        1
  •  4
  •   SirDarius    7 年前

    这里的一个简单解决方案是做相反的断言:

    assert!(return_with_fields() != MyEnum::WithoutFields);
    

    或者更简单地说:

    assert_ne!(return_with_fields(), MyEnum::WithoutFields);
    

    当然,如果枚举中有更多的成员,则必须添加更多的断言以涵盖所有可能的情况。

    或者,这就是欧普可能想到的,因为 assert! 如果失败,测试可以使用模式匹配和调用 panic! 万一出了什么问题:

    match return_with_fields() {
        MyEnum::WithFields {..} => {},
        MyEnum::WithoutFields => panic!("expected WithFields, got WithoutFields"),
    }
    
        2
  •  2
  •   Shepmaster Tim Diekmann    7 年前

    可以使原始代码与新宏一起使用:

    macro_rules! is_enum_variant {
        ($v:expr, $p:pat) => (
            if let $p = $v { true } else { false }
        );
    }
    
    #[test]
    fn example() {
        assert!(is_enum_variant!(return_with_fields(), MyEnum::WithoutFields {..}));
    }
    

    就我个人而言,我倾向于在我的枚举中添加方法:

    fn is_with_fields(&self) -> bool {
        match self {
            MyEnum::WithFields { .. } => true,
            _ => false,
        }
    }
    

    我也倾向于避免像枚举这样的结构,而是投入额外的工作:

    enum MyEnum {
        WithoutFields,
        WithFields(WithFields),
    }
    
    struct WithFields { field: String }
    
    impl MyEnum {
        fn is_with_fields(&self) -> bool {
            match self {
                MyEnum::WithFields(_) => true,
                _ => false,
            }
        }
    
        fn as_with_fields(&self) -> Option<&WithFields> {
            match self {
                MyEnum::WithFields(x) => Some(x),
                _ => None,
            }
        }
    
        fn into_with_fields(self) -> Option<WithFields> {
            match self {
                MyEnum::WithFields(x) => Some(x),
                _ => None,
            }
        }
    }
    

    我希望有朝一日,枚举变量可以成为自己的类型,以避免这个额外的结构。

    推荐文章