Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Встроенные функции — это функции, которые интегрируются непосредственно в вызывающий код.
Использование встроенных функций
При использовании параметров статического типа все функции, параметризованные параметрами типа, должны быть встроенными. Это гарантирует, что компилятор может разрешать эти параметры типа. При использовании обычных параметров универсального типа нет такого ограничения.
Кроме включения ограничений элементов, встроенные функции могут быть полезны при оптимизации кода. Однако чрезмерное использование встроенных функций может привести к снижению устойчивости кода к изменениям в оптимизации компилятора и реализации функций библиотеки. По этой причине следует избегать использования встроенных функций для оптимизации, если вы не пробовали все другие методы оптимизации. Создание функции или встроенного метода иногда может повысить производительность, но это не всегда так. Поэтому следует также использовать измерения производительности, чтобы убедиться, что выполнение любой встроенной функции фактически имеет положительный эффект.
Модификатор inline можно применять к функциям на верхнем уровне, на уровне модуля или на уровне метода в классе.
В следующем примере кода показана встроенная функция на верхнем уровне, встроенный метод экземпляра и встроенный статический метод.
let inline increment x = x + 1
type WrapInt32() =
member inline this.incrementByOne(x) = x + 1
static member inline Increment(x) = x + 1
Встроенные функции и вывод типов
Наличие inline вывода типа. Это связано с тем, что встроенные функции могут иметь статически разрешенные параметры типа, в то время как не встроенные функции не могут. В следующем примере кода показано, что inline полезно использовать функцию, которая имеет статически разрешенный параметр типа, float оператор преобразования.
let inline printAsFloatingPoint number =
printfn "%f" (float number)
inline Без модификатора вывод типов заставляет функцию принимать определенный тип в данном случаеint. Но при использовании inline модификатора функция также выводится для статического разрешения параметра типа.
inline При использовании модификатора тип выводится следующим образом:
^a -> unit when ^a : (static member op_Explicit : ^a -> float)
Это означает, что функция принимает любой тип, поддерживающий преобразование в float.
InlineIfLambda
Компилятор F# включает оптимизатор, выполняющий встраивание кода. Атрибут InlineIfLambda позволяет коду при необходимости указывать, что, если аргумент определяется лямбда-функцией, то этот аргумент всегда должен быть вложен на сайтах вызовов. Дополнительные сведения см. в статье F# RFC FS-1098.
Например, рассмотрим следующую iterateTwice функцию для обхода массива:
let inline iterateTwice ([<InlineIfLambda>] action) (array: 'T[]) =
for i = 0 to array.Length-1 do
action array[i]
for i = 0 to array.Length-1 do
action array[i]
Если сайт вызова:
let arr = [| 1.. 100 |]
let mutable sum = 0
arr |> iterateTwice (fun x ->
sum <- sum + x)
Затем после встраивание и другие оптимизации код становится следующим:
let arr = [| 1..100 |]
let mutable sum = 0
for i = 0 to arr.Length - 1 do
sum <- sum + arr[i]
for i = 0 to arr.Length - 1 do
sum <- sum + arr[i]
Эта оптимизация применяется независимо от размера лямбда-выражения. Эту функцию также можно использовать для реализации отмены циклов и аналогичных преобразований более надежно.
Предупреждение о выборе (/warnon:3517 или свойство <WarnOn>3517</WarnOn>) можно включить, чтобы указать места в коде, где InlineIfLambda аргументы не привязаны к лямбда-выражениям на сайтах вызовов. В обычных ситуациях это предупреждение не должно быть включено. Однако в некоторых типах высокопроизводительного программирования может быть полезно убедиться, что весь код встраиваются и неструктурированы.
Оптимизация курированных обратных вызовов
Чтобы избежать повторной адаптации arity, когда обратный вызов не может быть вложен, F# 11 поддерживается OptimizeClosureIfNotInlined вместе с InlineIfLambda:
let inline foldItems
([<InlineIfLambda; OptimizeClosureIfNotInlined>] folder)
state
(items: 'T[]) =
let mutable total = state
for item in items do
total <- folder total item
total
Функция должна быть встроенной, оба атрибута должны присутствовать, и обратный вызов должен быть курирован с двумя до пяти аргументов. Известный лямбда- Непрозрачный обратный вызов можно адаптировать один раз. Для этого требуется поддержка FSharp.Core 11 и компилятора, но не гарантирует нулевое выделение.
Отладка встроенных функций
Чтобы перейти в встроенные вспомогательные службы, скомпилируйте без оптимизации и сохраняйте сведения об отладке. F# 11 предпочитает обычные вызовы в следующих сборках:
let inline addFee (fee: decimal) (amount: decimal) =
let total = amount + fee
total
let invoiceTotal = addFee 2m 40m
printfn "%M" invoiceTotal
// 42
В примере проекта задайте точку let totalостанова , шаг в addFeeи проверьте его аргументы.
Оптимизированные сборки по-прежнему встроенные по умолчанию. Некоторые конструкции, включая возобновление кода и операций, требующих статического расширения, должны быть встроенны даже без оптимизации. Используется --always-inline для запроса более старого поведения.
Встроенные ограничения расширения в библиотеках
F# 11.2 может использовать открытые члены расширения для удовлетворения требований SRTP. Сведения о параметрах языка, области и требованиях к библиотеке см. в разделе "Члены расширения" для ограничений SRTP .