Встраиваемые функции

Встроенные функции — это функции , которые интегрируются непосредственно в вызывающий код.

Использование встроенных функций

При использовании параметров статического типа все функции, параметризованные параметрами типа, должны быть встроенными. Это гарантирует, что компилятор может разрешать эти параметры типа. При использовании обычных параметров универсального типа нет такого ограничения.

Кроме включения ограничений элементов, встроенные функции могут быть полезны при оптимизации кода. Однако чрезмерное использование встроенных функций может привести к снижению устойчивости кода к изменениям в оптимизации компилятора и реализации функций библиотеки. По этой причине следует избегать использования встроенных функций для оптимизации, если вы не пробовали все другие методы оптимизации. Создание функции или встроенного метода иногда может повысить производительность, но это не всегда так. Поэтому следует также использовать измерения производительности, чтобы убедиться, что выполнение любой встроенной функции фактически имеет положительный эффект.

Модификатор 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 аргументы не привязаны к лямбда-выражениям на сайтах вызовов. В обычных ситуациях это предупреждение не должно быть включено. Однако в некоторых типах высокопроизводительного программирования может быть полезно убедиться, что весь код встраиваются и неструктурированы.

См. также