问题描述
我了解Fn(大写F)特征: Fn
, FnMut
, FnOnce
.我了解它们是特质,并且像特质一样工作.
I have a grasp of the Fn (capital-F) traits: Fn
, FnMut
, FnOnce
. I understand that they are traits and work like traits.
但是 fn
(小写的-f)呢?在编辑器中它的颜色不同,这告诉我这不是特质.它也可以在其他地方无法使用的地方使用(反之亦然),尽管在其他情况下它的表现也类似.我找不到直接在文档中对其进行解释的内容.
But what about fn
(lowercase-f)? It gets a different coloring in editors, which tells me it's not a trait. It can also be used in some places where the others can't (and vice-versa), though it seems to behave similarly in other cases. I couldn't find anything explaining it directly in the docs.
推荐答案
prog-fh的答案本质上是正确的,但是缺乏细微差别.Rust具有三种类似于函数的类型:
prog-fh's answer is essentially correct, but lacks some nuance. Rust has three kinds of function-like types:
-
功能项 是使用
fn foo(){...}
创建函数时得到的结果.它也是类似元组的struct或enum变体的构造函数的类型.函数项的大小为零(它们不包含任何数据),并且每个非泛型函数都有唯一的,无法命名的函数项类型.在错误消息中,编译器将显示这些"Voldemort类型".如fn()->(){foo}
(函数名称在{}
中).
Function items are what you get when you create a function by using
fn foo() {...}
. It's also the type of the constructor of a tuple-like struct or enum variant. Function items are zero-sized (they contain no data), and every non-generic function has a unique, unnameable function item type. In error messages, the compiler displays these "Voldemort types" as something likefn() -> () {foo}
(with the name of the function in{}
).
关闭 是类似于函数项的值,但是闭包可能包含数据:它们从环境中捕获的任何变量的副本或引用.如您所知,您可以使用闭包语法( | args |表达式
)创建一个闭包.像函数项一样,闭包具有唯一的,无法命名的类型(由编译器呈现为 [closure@src/main.rs:4:11:4:23]
之类的东西).
Closures are values similar to function items, but closures may contain data: copies of or references to whatever variables they capture from their environment. As you already know, you create a closure by using closure syntax (|args| expression
). Like function items, closures have unique, unnameable types (rendered by the compiler something like [closure@src/main.rs:4:11: 4:23]
).
函数指针 是您要问的问题:类似于 fn()->的类型.()
.函数指针不能包含数据,但是大小不能为零.顾名思义,它们是指针.函数指针可以指向函数项,也可以指向不捕获任何内容的闭包,但不能为空.
Function pointers are what you're asking about: the types that look like fn() -> ()
. Function pointers cannot contain data, but they are not zero-sized; as their name suggests, they are pointers. A function pointer may point either to a function item, or to a closure that captures nothing, but it cannot be null.
在可能的情况下,函数项和闭包会自动强制转换为相关的函数指针类型,这就是为什么 let f:fn(i32)= | _ |();
的工作原理:由于闭包没有捕获任何内容,因此可以将其强制转换为函数指针.
Function items and closures are automatically coerced to the relevant function pointer type when possible, so that's why let f: fn(i32) = |_| ();
works: because the closure captures nothing, it can be coerced to a function pointer.
所有三种类似于函数的类型均实现相关的 Fn
, FnMut
和 FnOnce
特征(除非闭包可能不实现 Fn
或 FnMut
(取决于它们捕获的内容).函数项和函数指针还实现 Copy
, Clone
, Send
和 Sync
(闭包仅在所有他们的内容呢.)
All three function-like types implement the relevant Fn
, FnMut
and FnOnce
traits (except that closures might not implement Fn
or FnMut
depending on what they capture). Function items and function pointers also implement Copy
, Clone
, Send
and Sync
(closures only implement these traits when all their contents do).
在性能方面,函数指针是泛型和特征对象之间的折衷方案.必须取消引用它们才能调用它们,因此调用函数指针可能比直接调用函数项或闭包慢,但仍比调用 dyn Fn
特征对象快,后者涉及到vtable查找.除了间接调用.
Performance-wise, function pointers are something of a compromise between generics and trait objects. They have to be dereferenced to be called, so calling a function pointer may be slower than calling a function item or closure directly, but still faster than calling a dyn Fn
trait object, which involves a vtable lookup in addition to the indirect call.
这篇关于在Rust中,什么是`fn()-> ;?()`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!