Las funciones de orden superior son muy útiles y realmente pueden mejorar el reusability
código. Sin embargo, una de las mayores preocupaciones sobre su uso es la eficiencia. Las expresiones Lambda se compilan en clases (a menudo clases anónimas) y la creación de objetos en Java es una operación pesada. Todavía podemos usar funciones de orden superior de una manera eficaz, manteniendo todos los beneficios, haciendo funciones en línea.
aquí viene la función en línea en la imagen
Cuando una función está marcada como inline
, durante la compilación del código, el compilador reemplazará todas las llamadas a la función con el cuerpo real de la función. Además, las expresiones lambda proporcionadas como argumentos se reemplazan con su cuerpo real. No se tratarán como funciones, sino como código real.
En resumen: - Inline -> en lugar de ser llamados, son reemplazados por el código del cuerpo de la función en tiempo de compilación ...
En Kotlin, usar una función como parámetro de otra función (las llamadas funciones de orden superior) se siente más natural que en Java.
Sin embargo, usar lambdas tiene algunas desventajas. Dado que son clases anónimas (y, por lo tanto, objetos), necesitan memoria (e incluso podrían aumentar el recuento general de métodos de su aplicación). Para evitar esto, podemos integrar nuestros métodos.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
Del ejemplo anterior : - Estas dos funciones hacen exactamente lo mismo: imprimir el resultado de la función getString. Uno está alineado y el otro no.
Si revisa el código java descompilado, verá que los métodos son completamente idénticos. Eso es porque la palabra clave en línea es una instrucción para el compilador para copiar el código en el sitio de llamada.
Sin embargo, si estamos pasando cualquier tipo de función a otra función como a continuación:
//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 eso, podemos reescribir nuestra función de la siguiente manera:
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)
/*...*/}
Supongamos que tenemos una función de orden superior como la siguiente:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Aquí, el compilador nos dirá que no usemos la palabra clave en línea cuando solo hay un parámetro lambda y lo estamos pasando a otra función. Entonces, podemos reescribir la función anterior de la siguiente manera:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Nota : -¡Tuvimos que eliminar la palabra clave noinline también porque solo se puede usar para funciones en línea!
Supongamos que tenemos una función como esta ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
Esto funciona bien, pero la esencia de la lógica de la función está contaminada con el código de medición, lo que dificulta que sus colegas trabajen en lo que está sucediendo. :)
Así es como una función en línea puede ayudar a este 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
}
Ahora puedo concentrarme en leer cuál es la intención principal de la función intercept () sin saltarme las líneas del código de medición. También nos beneficiamos de la opción de reutilizar ese código en otros lugares donde queramos
inline le permite llamar a una función con un argumento lambda dentro de un cierre ({...}) en lugar de pasar la medida lambda como (myLamda)