Pregunta ¿Por qué Rust's assert_eq! implementado usando un partido?


Aquí está Rust's assert_eq! implementación macro. He copiado solo la primera rama por brevedad:

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)
                }
            }
        }
    });
}

¿Cuál es el propósito de la match ¿aquí? ¿Por qué no es suficiente verificar la falta de igualdad?


32
2018-02-11 13:57


origen


Respuestas:


De acuerdo, eliminemos la coincidencia.

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

Ahora, vamos a elegir un ejemplo completamente al azar ...

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);

Esto se expandiría a ...

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

Como pueden ver, estamos llamando a la función dos veces. Eso es menos que ideal, más aún si el resultado de la función puede cambiar cada vez que se invoca.

los match es solo una forma rápida y sencilla de evaluar ambos "argumentos" a la macro exactamente una vez y vincularlos a los nombres de las variables.


44
2018-02-11 14:26