function - what - when use inline kotlin




quando usar uma função inline em Kotlin? (2)

Deixe-me adicionar: "Quando não usar inline " :

1) Se você tem uma função simples que não aceita outras funções como argumento, não faz sentido integrá-las. IntelliJ irá avisá-lo:

O impacto esperado no desempenho de inlining '...' é insignificante. Inlining funciona melhor para funções com parâmetros de tipos funcionais

2) Mesmo se você tiver uma função "com parâmetros de tipos funcionais", você pode encontrar o compilador dizendo que o inlining não funciona. Considere este exemplo:

inline fun calculateNoInline(param: Int, operation: IntMapper): Int {
    val o = operation //compiler does not like this
    return o(param)
}

Este código não irá compilar com o erro:

Uso ilegal do parâmetro inline 'operation' em '...'. Adicione o modificador 'noinline' à declaração de parâmetro.

A razão é que o compilador é incapaz de inline este código. Se a operation não estiver envolvida em um objeto (o que é implícito por inline desde que você queira evitar isso), como ela pode ser atribuída a uma variável? Nesse caso, o compilador sugere tornar o argumento noinline . Ter uma função inline com uma única função noinline não faz nenhum sentido, não faça isso. No entanto, se houver vários parâmetros de tipos funcionais, considere inlining alguns deles, se necessário.

Então, aqui estão algumas regras sugeridas:

  • Você pode inline quando o tipo funcional param é chamado diretamente ou passado para outra função inline
  • Você deve inline quando ^ é o caso.
  • Você não pode inline quando o parâmetro de função está sendo atribuído à variável dentro da função
  • Você deve considerar inlining se pelo menos um de seus parâmetros digitados funcionais puder ser noinline , use noinline para o resto.
  • Você não deve inline funções enormes, pense no código de byte gerado. Ele será copiado para todos os lugares dos quais a função é chamada.
  • Outro caso de uso é o tipo de parâmetro reified , que exige que você use inline . Leia here

Eu sei que uma função inline talvez melhore o desempenho e faça com que o código gerado cresça, mas não tenho certeza de quando ele está correto para usá-lo.

lock(l) { foo() }

Em vez de criar um objeto de função para o parâmetro e gerar uma chamada, o compilador poderia emitir o código a seguir. ( Source )

l.lock()
try {
  foo()
}
finally {
  l.unlock()
}

mas descobri que não há objeto de função criado pelo kotlin para uma função não-inline. porque?

/**non-inline function**/
fun lock(lock: Lock, block: () -> Unit) {
    lock.lock();
    try {
        block();
    } finally {
        lock.unlock();
    }
}

Digamos que você crie uma função de ordem mais alta que tome um lambda de type () -> Unit (sem parâmetros, sem valor de retorno) e execute da seguinte forma:

fun nonInlined(block: () -> Unit) {
    println("before")
    block()
    println("after")
}

No jargão de Java, isso vai se traduzir em algo parecido com isto (simplificado!):

public void nonInlined(Function block) {
    System.out.println("before");
    block.invoke();
    System.out.println("after");
}

E quando você liga de Kotlin ...

nonInlined {
    println("do something here")
}

Sob o capô, uma instância da Function será criada aqui, que envolve o código dentro do lambda (novamente, isso é simplificado):

nonInlined(new Function() {
    @Override
    public void invoke() {
        System.out.println("do something here");
    }
});

Então, basicamente, chamar essa função e passar um lambda para ela sempre criará uma instância de um objeto Function .

Por outro lado, se você usar a palavra-chave inline :

inline fun inlined(block: () -> Unit) {
    println("before")
    block()
    println("after")
}

Quando você liga assim:

inlined {
    println("do something here")
}

Nenhuma instância da Function será criada, em vez disso, o código em torno da invocação do block dentro da função inlined será copiado para o site da chamada, portanto, você obterá algo parecido com isso no bytecode:

System.out.println("before");
System.out.println("do something here");
System.out.println("after");

Nesse caso, nenhuma nova instância é criada.





inline-functions