【问题标题】:How to avoid code duplication when comparing two enums' variants and their values?比较两个枚举变量及其值时如何避免代码重复?
【发布时间】:2019-02-09 13:26:47
【问题描述】:

我需要比较两个serde_json::Values:

enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

比较会返回另一个枚举:

enum Diff {
    Equal,
    Different,
    NotFound,
}

我开始编写如下结构的代码:

fn compare(val1: &Value, val2: &Value) {
    let cmp = match val1 {
        Value::Null => {
            if let Value::Null = val2 {
                Diff::Equal
            } else {
                Diff::NotFound
            }
        }
        Value::Bool(b1) => {
            if let Value::Bool(b2) = val2 {
                if b1 == b2 {
                    Diff::Equal
                } else {
                    Diff::Different
                }
            } else {
                Diff::NotFound
            }
        }
        Value::Number(ref n1) => {
            if let Value::Number(ref n2) = val2 {
                if n1 == n2 {
                    Diff::Equal
                } else {
                    Diff::Different
                }
            } else {
                Diff::NotFound
            }
        }
        Value::String(ref s1) => {
            if let Value::String(ref s2) = val2 {
                if s1 == s2 {
                    Diff::Equal
                } else {
                    Diff::Different
                }
            } else {
                Diff::NotFound
            }
        }
        _ => {
            // etc...
            Diff::NotFound
        }
    };

}

我想避免很多代码重复。

  1. 一般来说有没有更好的方法来比较枚举?
  2. 如何避免这种类型的重复(例如,在 C++ 中您可以使用宏)

【问题讨论】:

  • 你能描述一下这个函数应该做什么吗?似乎您在值相等时返回Equal,当值不同但具有相同变体时返回Different,当变体不同时返回NotFound,这似乎是一个奇怪的名称。你能确认一下吗?
  • @mcarton 是的,你是对的,NotFound 是一个坏名字,但基本上我想区分两个 JSON 节点时 1) 具有相同的键和值,2) 具有相同的键但不同的值,3)具有相同的键但不同的类型/变体(例如,第一个是数字,第二个是字符串),4)(不在代码中)node1 中的键在 node2 中不存在,反之亦然.
  • play.integer32.com/…,您可以这样做并使用宏实现它。
  • 你可以#[derive(PartialEq)],如果不相等,你可以再做一次检查。将帮助您获得“正确”的支票

标签: enums rust comparison


【解决方案1】:

您可以同时匹配 2 个值:

let cmp = match (val1, val2) {
    (Value::Null, Value::Null) => Diff::Equal,
    _ => {
        // etc...
        Diff::NotFound
    }
};

您还可以实现转换函数或特征并使用它:

impl Diff {
    fn new<T: PartialEq>(lhs: T, rhs: T) -> Diff {
        if lhs == rhs { Diff::Equal } else { Diff::Different }
    }
}

fn compare(val1: &Value, val2: &Value) {
    let cmp = match (val1, val2) {
        (Value::Null, Value::Null) => Diff::Equal,
        (Value::Bool(b1), Value::Bool(b2)) => Diff::new(b1, b2),
        _ => Diff::NotFound,
    };
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-08
    • 2011-10-06
    • 2023-01-12
    相关资源
    最近更新 更多