As funções de ordem superior são muito úteis e podem realmente melhorar o funcionamento reusability
do código. No entanto, uma das maiores preocupações em usá-los é a eficiência. As expressões lambda são compiladas em classes (geralmente classes anônimas), e a criação de objetos em Java é uma operação pesada. Ainda podemos usar funções de ordem superior de forma eficaz, mantendo todos os benefícios, tornando as funções embutidas.
aqui vem a função embutida em imagem
Quando uma função é marcada como inline
, durante a compilação do código, o compilador substituirá todas as chamadas de função pelo corpo real da função. Além disso, as expressões lambda fornecidas como argumentos são substituídas por seu corpo real. Eles não serão tratados como funções, mas como código real.
Resumindo: - Inline -> em vez de serem chamados, eles são substituídos pelo código do corpo da função em tempo de compilação ...
Em Kotlin, usar uma função como parâmetro de outra função (as chamadas funções de ordem superior) parece mais natural do que em Java.
Usar lambdas tem algumas desvantagens, entretanto. Como são classes anônimas (e, portanto, objetos), elas precisam de memória (e podem até aumentar a contagem geral de métodos do seu aplicativo). Para evitar isso, podemos embutir nossos métodos.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
Do exemplo acima : - Essas duas funções fazem exatamente a mesma coisa - imprimir o resultado da função getString. Um está embutido e o outro não.
Se você verificar o código java descompilado, verá que os métodos são completamente idênticos. Isso ocorre porque a palavra-chave inline é uma instrução para o compilador copiar o código para o site de chamada.
No entanto, se estivermos passando qualquer tipo de função para outra função como abaixo:
//Compile time error… Illegal usage of inline function type ftOne...
inline fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Para resolver isso, podemos reescrever nossa função conforme abaixo:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Suponha que tenhamos uma função de ordem superior como abaixo:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Aqui, o compilador nos dirá para não usar a palavra-chave inline quando houver apenas um parâmetro lambda e o estivermos passando para outra função. Portanto, podemos reescrever a função acima como abaixo:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Nota : - tivemos que remover a palavra-chave noinline também porque ela só pode ser usada para funções inline!
Suponha que tenhamos uma função como esta ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
Isso funciona bem, mas a essência da lógica da função está poluída com o código de medição, tornando mais difícil para seus colegas trabalharem o que está acontecendo. :)
Veja como uma função embutida pode ajudar neste código:
fun intercept() {
// ...
val result = measure { doSomethingWeWantToMeasure() }
// ...
}
inline fun <T> measure(action: () -> T) {
val start = SystemClock.elapsedRealtime()
val result = action()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
return result
}
Agora posso me concentrar em ler qual é a principal intenção da função intercept () sem pular as linhas do código de medição. Também nos beneficiamos da opção de reutilizar esse código em outros lugares onde queremos
inline permite que você chame uma função com um argumento lambda dentro de um encerramento ({...}) em vez de passar a medida lambda like (myLamda)