Почему Rust assert_eq! реализовано с использованием соответствия?

Здесь Rust assert_eq! макро-реализация. Для краткости я скопировал только первую ветку:

macro_rules! assert_eq {
    ($left:expr, $right:expr) => ({
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    panic!(r#"assertion failed: '(left == right)'
  left: '{:?}',
 right: '{:?}'"#, left_val, right_val)
                }
            }
        }
    });
}

Какова цель match здесь? Почему не проверяется недостаточно для равенства?

Ответы

Ответ 1

Хорошо, позвольте удалить матч.

    macro_rules! assert_eq_2 {
        ($left:expr, $right:expr) => ({
            if !($left == $right) {
                panic!(r#"assertion failed: '(left == right)'
  left: '{:?}',
 right: '{:?}'"#, $left, $right)
            }
        });
    }

Теперь позвольте выбрать совершенно случайный пример...

fn really_complex_fn() -> i32 {
    // Hit the disk, send some network requests,
    // and mine some bitcoin, then...
    return 1;
}

assert_eq_2!(really_complex_fn(), 1);

Это расширилось бы до...

{
    if !(really_complex_fn() == 1) {
        panic!(r#"assertion failed: '(left == right)'
  left: '{:?}',
 right: '{:?}'"#, really_complex_fn(), 1)
    }
}

Как вы можете видеть, мы вызываем функцию дважды. Это меньше, чем идеально, тем более, если результат функции может меняться каждый раз, когда он называется.

match - это просто быстрый и простой способ оценить оба аргумента макроса ровно один раз и привязать их к именам переменных.