Funções em linha
As funções em linha são funções que são integradas diretamente no código de chamada.
Usando funções embutidas
Quando você usa parâmetros de tipo estático, todas as funções parametrizadas por parâmetros de tipo devem estar embutidas. Isso garante que o compilador possa resolver esses parâmetros de tipo. Quando você usa parâmetros de tipo genéricos comuns, não há essa restrição.
Além de permitir o uso de restrições de membros, as funções embutidas podem ser úteis na otimização do código. No entanto, o uso excessivo de funções embutidas pode fazer com que seu código seja menos resistente a alterações nas otimizações do compilador e na implementação de funções de biblioteca. Por esse motivo, você deve evitar o uso de funções em linha para otimização, a menos que tenha tentado todas as outras técnicas de otimização. Tornar uma função ou método em linha pode, por vezes, melhorar o desempenho, mas nem sempre é esse o caso. Portanto, você também deve usar medições de desempenho para verificar se tornar qualquer função em linha tem, de fato, um efeito positivo.
O inline
modificador pode ser aplicado a funções no nível superior, no nível do módulo ou no nível do método em uma classe.
O exemplo de código a seguir ilustra uma função embutida no nível superior, um método de instância embutida e um método estático embutido.
let inline increment x = x + 1
type WrapInt32() =
member inline this.incrementByOne(x) = x + 1
static member inline Increment(x) = x + 1
Funções embutidas e inferência de tipo
A presença de afetos de inferência de inline
tipo. Isso ocorre porque as funções embutidas podem ter parâmetros de tipo resolvidos estaticamente, enquanto as funções não embutidas não podem. O exemplo de código a seguir mostra um caso em inline
que é útil porque você está usando uma função que tem um parâmetro de tipo resolvido estaticamente, o float
operador de conversão.
let inline printAsFloatingPoint number =
printfn "%f" (float number)
Sem o modificador, a inline
inferência de tipo força a função a tomar um tipo específico, neste caso int
. Mas com o inline
modificador, a função também é inferida para ter um parâmetro de tipo resolvido estaticamente. Com o inline
modificador, infere-se que o tipo é o seguinte:
^a -> unit when ^a : (static member op_Explicit : ^a -> float)
Isso significa que a função aceita qualquer tipo que suporte uma conversão para float.
InlineIfLambda
O compilador F# inclui um otimizador que executa o inlining de código. O InlineIfLambda
atributo permite que o código indique opcionalmente que, se um argumento é determinado como uma função lambda, então esse argumento deve sempre ser embutido em sites de chamada. Para obter mais informações, consulte F# RFC FS-1098.
Por exemplo, considere a seguinte iterateTwice
função para atravessar uma matriz:
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]
Se o site de chamada for:
let arr = [| 1.. 100 |]
let mutable sum = 0
arr |> iterateTwice (fun x ->
sum <- sum + x)
Depois de inline e outras otimizações, o código se torna:
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]
Essa otimização é aplicada independentemente do tamanho da expressão lambda envolvida. Esse recurso também pode ser usado para implementar o desenrolamento de loops e transformações semelhantes de forma mais confiável.
Um aviso de aceitação (/warnon:3517
ou propriedade <WarnOn>3517</WarnOn>
) pode ser ativado para indicar locais em seu código onde InlineIfLambda
os argumentos não estão vinculados a expressões lambda em sites de chamada. Em situações normais, este aviso não deve ser ativado. No entanto, em certos tipos de programação de alto desempenho, pode ser útil garantir que todo o código seja embutido e nivelado.