Что такое `fn () -> ()` в Rust?
У меня есть схватывание Fn (капитальное-F) черты: Fn, FnMut, FnOnce. Я понимаю, что это черты характера и работают как черты.
Но как насчет fn(строчная-f)? В редакторах он получает другую окраску, что говорит мне, что это не черта. Его также можно использовать в некоторых местах, где другие не могут (и наоборот), хотя, похоже, в других случаях он ведет себя аналогичным образом. Я не мог найти ничего, что объясняло бы это прямо в документации.
Ответы
Ответ prog-fh, по сути, правильный, но без нюансов. В Rust есть три типа функционально-подобных типов:
Функциональные элементы - это то, что вы получаете, когда создаете функцию с помощью
fn foo() {...}. Это также тип конструктора структуры, подобной кортежу, или варианта перечисления. Функциональные элементы имеют нулевой размер (они не содержат данных), и каждая неуниверсальная функция имеет уникальный безымянный тип функционального элемента. В сообщениях об ошибках компилятор отображает эти «типы Волан-де-Морта» как нечто вродеfn() -> () {foo}(с именем функции внутри{}).Замыкания - это значения, похожие на функциональные элементы, но замыкания могут содержать данные: копии или ссылки на любые переменные, которые они захватывают из своей среды. Как вы уже знаете, вы создаете замыкание, используя синтаксис замыкания (
|args| expression). Подобно элементам функций, замыкания имеют уникальные безымянные типы (которые компилятор отображает что-то вроде[closure@src/main.rs:4:11: 4:23]).Указатели функций - это то, о чем вы спрашиваете: типы, на которые они похожи
fn() -> (). Указатели функций не могут содержать данные, но они не нулевого размера; как следует из их названия, они являются указателями. Указатель функции может указывать либо на элемент функции, либо на замыкание, которое ничего не захватывает, но не может быть нулевым.
Функциональные элементы и замыкания автоматически приводятся к соответствующему типу указателя функции, когда это возможно, поэтому это let f: fn(i32) = |_| ();работает: поскольку замыкание ничего не захватывает, оно может быть принудительно приведено к указателю функции.
Все три функции, такие как типы реализации соответствующей Fn, FnMutи FnOnceчерты характера ( за исключением того, что закрытия не может реализовать Fnили в FnMutзависимости от того, что они захвата). Функциональные элементы и указатели на функции также реализуют Copy, Clone, Sendи Sync(укупорочные только реализовать эти черты , когда все их содержимое делают).
С точки зрения производительности указатели на функции являются чем-то вроде компромисса между универсальными типами и типажными объектами. Для их вызова необходимо разыменовать их, поэтому вызов указателя функции может быть медленнее, чем прямой вызов элемента функции или закрытия, но все же быстрее, чем вызов dyn Fnобъекта-признака, который включает поиск vtable в дополнение к косвенному вызову.
Рекомендации
- В чем практическая разница между элементом fn и указателем fn?
- Зачем создавать язык с уникальными анонимными типами?
- Как создать структуру для FFI, содержащую указатель на функцию, допускающий значение NULL?
- Почему передача закрытия функции, которая принимает указатель на функцию, не работает?
Это тип указателя на функцию .
Он относится только к функции, а не к замыканию, поскольку содержит только адрес функции, а не захваченное окружение, которое требуется замыканию.
FnЧерта (капитал F) может относиться либо к закрытию или функции.
fn - это тип указателя на функцию. См. Также здесь в документации:https://doc.rust-lang.org/std/primitive.fn.html