第一次看到 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!