Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing functions for equality in Rust

I have a function which takes a number as an argument, and then returns a function based on the number. Depending on many different things, it might return any of ~50 functions, and the cases for which one it should return get pretty complicated. As such, I want to build some tests to make sure the proper functions are being returned. What I have so far looks roughly like this.

fn pick_a_function(decider: u32) -> fn(&mut SomeStruct) {
    match decider {
        1 => add,
        2 => sub,
        _ => zero,
    }
}

fn add(x: &mut SomeStruct) {
    x.a += x.b;
}

fn sub(x: &mut SomeStruct) {
    x.a -= x.b;
}

fn zero(_x: &mut SomeStruct) {
    x.a = 0;
}

fn main() {
    let mut x = SomeStruct { a: 2, b: 3 };
    pick_a_function(1)(&mut x);

    println!("2 + 3 = {}", x.a);
}

#[cfg(test)]
mod tests {
    use super::*;

    fn picks_correct_function() {
        assert_eq!(pick_a_function(1), add);
    }
}

The problem is that the functions don't seem to implement the Eq or PartialEq traits, so assert_eq! just says that it can't compare them. What options do I have for comparing the returned function to the correct function?

like image 398
McKayla Avatar asked May 14 '26 05:05

McKayla


1 Answers

So it turns of that functions in Rust actually do implement PartialEq as long as there is not a lifetime attached, and as long as the function takes less than 10 arguments. This restriction is because each form of function signature has to have the traits implemented directly, because the compiler considers all of them to be completely unrelated types.

The functions I was returning took a mutable reference to a struct, which implicitly gives the function a lifetime, so they no longer had a type signature which implemented PartialEq. All that rust really does internally to compare function equality though is cast both of them to pointers and then compare, so we can actually just do the same thing.

#[cfg(test)]
mod tests {
    use super::*;

    fn picks_correct_function() {
        assert_eq!(
            pick_a_function(1) as usize,
            add as usize
        );
    }
}
like image 128
McKayla Avatar answered May 17 '26 06:05

McKayla



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!