Rust 的函数指针比较:fn_addr_eq

第一次看到 Rust 标准库中的 ptr::fn_addr_eq 函数,第一反应是:这不就是 == 的别名吗?为什么要专门为函数指针比较创建一个新函数?

表面上的等价性

从功能角度看,fn_addr_eq(f, g) 确实等同于 f == g

use std::ptr;

fn hello() { println!("Hello"); }
fn world() { println!("World"); }

// 这两种写法功能完全相同
assert_eq!(hello as fn() == world as fn(), false);
assert_eq!(ptr::fn_addr_eq(hello as fn(), world as fn()), false);

既然功能相同,为什么要多此一举呢?

语义的明确性问题

实际上,函数指针比较比较的是内存地址,而不是逻辑等价性(这就是为什么这个函数叫fn_addr_eq)。

这就产生了理解上的偏差,一部分人会认为这是在比较函数体是否逻辑等价。

但是编译器会有更复杂的情况,,编译器优化会导致一些反直觉的结果,例如会为逻辑等价的函数合并为同一个函数(减小代码体积):

意外的 true:函数合并

use std::ptr;

fn main() {
    let f: fn(i32) -> i32 = |x| x;
    let g: fn(i32) -> i32 = |x| x + 0;  // 不同的闭包,不同的函数体

    println!("{}", ptr::fn_addr_eq(f, g));
    println!("{}", f == g);
}

上方代码在release后,f==g将为true!!在debug模式下为false!

Debug

Release