Как избежать дублирования кода при сравнении двух вариантов перечислений и их значений? - PullRequest
0 голосов
/ 09 февраля 2019

Мне нужно сравнить два serde_json::Value с:

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 ++ вы можете использовать макрос, например)

1 Ответ

0 голосов
/ 09 февраля 2019

Вы можете сопоставить 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,
    };
}
...