Primitive Type fn1.0.0[−]
Expand description
函数指针,例如 fn(usize) -> bool
。
另请参见 traits Fn
,FnMut
和 FnOnce
。
函数指针是指向 code 的指针,而不是数据。它们可以像函数一样被调用。
像引用一样,函数指针除其他外被假定为非 null,因此,如果您想在 FFI 上传递函数指针并能够容纳 null 指针,请使 Option<fn()>
类型具有所需的签名。
Safety
普通函数指针是通过强制转换不能捕获环境的普通函数或闭包而获得的:
fn add_one(x: usize) -> usize { x + 1 } let ptr: fn(usize) -> usize = add_one; assert_eq!(ptr(5), 6); let clos: fn(usize) -> usize = |x| x + 5; assert_eq!(clos(5), 10);Run
除了根据其签名而有所不同外,函数指针还具有两种形式: 安全和不安全。
普通 fn()
函数指针只能指向安全函数,而 unsafe fn()
函数指针可以指向安全或不安全函数。
fn add_one(x: usize) -> usize { x + 1 } unsafe fn add_one_unsafely(x: usize) -> usize { x + 1 } let safe_ptr: fn(usize) -> usize = add_one; // ERROR: 不匹配的类型: 预期正常 fn,发现不安全 fn let bad_ptr: fn(usize) -> usize=add_one_unsafely; let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely; let really_safe_ptr: unsafe fn(usize) -> usize = add_one;Run
ABI
最重要的是,函数指针可以根据它们使用的 ABI 有所不同。这是通过在类型之前添加 extern
关键字,然后是所涉及的 ABI 来实现的。
默认的 ABI 是 “Rust”,即 fn()
是与 extern "Rust" fn()
完全相同的类型。
指向带有 C ABI 的函数的指针的类型为 extern "C" fn()
。
extern "ABI" { ... }
块使用 ABI “ABI” 声明函数。此处的默认值为 “C”,即,在 extern {...}
块中声明的函数具有 “C” ABI。
有关更多信息和受支持的 ABI 列表,请参见 the nomicon’s section on foreign calling conventions。
可变函数
“C” 或 “cdecl” ABI 的 Extern 函数声明也可以 variadic,允许使用可变数量的参数来调用它们。普通的 Rust 函数,即使是 extern "ABI"
的函数,也不能可变。
有关更多信息,请参见 关于可变参数函数的 nomicon 部分。
创建函数指针
如果 bar
是函数的名称,则表达式 bar
不是 函数指针。相反,它表示唯一标识函数 bar
的无法命名类型的值。
该值的大小为零,因为该类型已经标识了该函数。
这样做的好处是 “calling” 值 (实现 Fn*
traits) 不需要动态分配。
零大小的类型 强制 到常规函数指针。例如:
use std::mem; fn bar(x: i32) {} let not_bar_ptr = bar; // `not_bar_ptr` 大小为零,唯一标识 `bar` assert_eq!(mem::size_of_val(¬_bar_ptr), 0); let bar_ptr: fn(i32) = not_bar_ptr; // 强制转换为函数指针 assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::<usize>()); let footgun = &bar; // 这是对标识 `bar` 的零大小类型的共享引用Run
最后一行显示 &bar
也不是函数指针。相反,它是特定于函数的 ZST 的引用。当 bar
是一个函数时,&bar
基本上不是您想要的。
Traits
函数指针实现以下 traits:
由于 Rust 的类型系统中的临时限制,这些 traits 仅在 "Rust"
和 "C"
ABI 上使用不超过 12 个参数的函数上实现。未来,这可能会改变。
另外,具有 any 签名,ABI 或 safety 的函数指针是 Copy
,并且所有 safe 函数指针都实现 Fn
,FnMut
和 FnOnce
。之所以可行,是因为这些 traits 是编译器特有的。