Funciones de orden superior en Kotlin: bajo el capó. | de Shangeeth Sivan | enero 2023
Funciones de orden superior en Kotlin: bajo el capó. | de Shangeeth Sivan | enero 2023
Imagen creada con photopeaVeamos una función simple con un parámetro de tipo funcional en Kotlin. En aras de la simplicidad, creé este método que acepta dos parámetros:
nombre del evento de tipo Cadena
finalizaciónOyente de la función Tipo que devuelve la Unidad.
fun insertEvent(eventName: String, completeListener: () -> Unit) { eventRepository.insert(eventName) // Piense en esto como un eventcompletionListener.invoke() aplazado. Vamos a convertir esto a código de bytes de Kotlin y descompilarlo a la versión de Java. Herramientas -> Kotlin -> Mostrar código de bytes -> Descompilar (Cómo vincular) public final void insertEvent(@NotNull String eventName, @NotNull Function0 completeListener) {Intrinsics.checkNotNullParameter(eventName, «eventName»);Intrinsics.checkNotNullParameter(completionListener, » completeListener»);this.eventRepository.insert(eventName);completionListener.invoke();}Desglosemos cada parámetro:
nombre del evento – El tipo de datos sigue siendo una cadena y se anota como @NonNull en Java; este parámetro parece simple.
finalizaciónOyente — el tipo de datos se ve raro y se llama Function0 ?? 🤔
¿Qué es Función0? Si hace Control-clic en Function0, navega a Functions.kt. Veamos qué contiene Functions.kt: interfaz pública Function0 : funciones {función de operador público invocar(): R}función de interfaz pública1 : funciones {operador público invocación divertida (p1: P1): R} función de interfaz pública2 : funciones {función de invocación de operador público (p1: P1, p2: P2): R}…Function0 no es más que una interfaz con método de invocación que tiene 0 parámetros. Function1 es otra interfaz con método de invocación que tiene 1 parámetro. Function2 es otra interfaz con método de invocación que tiene 2 parámetros, continúa hasta Function22So debajo de este capó, nuestra función de orden superior finalizaciónOyente ha sido reemplazado por Function0 de Kotlin. Si sabe un poco sobre genéricos, debería poder imaginar qué P1, P2, … y R en Functions.ktP1, P2, … son los tipos genéricos para los parámetros de finalizaciónOyenteR en nuestro caso es el tipo de retorno genérico para el tipo de retorno de la función CompletionListener’s Tipo de retorno Si aún no puede imaginar lo que está sucediendo, intente llamar a la misma función que creó en Kotlin desde un archivo de Java para que pueda visualizar cómo funciona de forma natural y el código de Kotlin también se puede usar sin problemas desde Java. //Llamando a la misma método de Java worldpublic static void main(String[] args){// Llamar al mismo insertEvent desde java worldeventHelper.insertEvent(«test», new Function0() {@Overridepublic Unit invocar() {return null;}});}Como puede ver arriba, tenemos que crear una clase interna anónima para la interfaz Function0 para obtener la devolución de llamada en el mundo de JavaOk, cambiemos finalizaciónOyente yagregue un parámetro: // eliminó el eventName paramfun insertEvent (completionListener: (test: String) -> Unit) {completionListener.invoke(«success»)}Este es el código generado: public final void insertEvent(@NotNull Function1 completeListener) { Intrinsics.checkNotNullParameter(completionListener, «completionListener»);completionListener.invoke(«success»);}funcion0 ahora es reemplazado por funcion1 para admitir el parámetro de cadena. Espero que este blog lo haya ayudado a comprender cómo funcionan las funciones de orden superior bajo el capó.Algunos conocimientos adicionales: Ok, ¿Kotlin admitirá cualquier número de parámetros en nuestras funciones de orden superior? Recibí esta pregunta cuando noté algo extraño en Functions.kt, hay interfaces de funciones hasta Function22. ¿Qué pasa si tengo más de 22 parámetros? ¿Kotlin arrojará un error de compilación? A ver… Cambiemos lo nuestro finalizaciónOyente tiene 23 parámetros. 😅// Eliminé el parámetro String y reemplacé el método de invocación con println.fun insertEvent(completionListener: (test1: String, test2: String, test3: String, test4: String, test5: String, test6: String, test7: String , prueba8: cadena, prueba9: cadena, prueba10: cadena, prueba11: cadena, prueba12: cadena, prueba13: cadena, prueba14: cadena, prueba15: cadena, prueba16: cadena, prueba17: cadena, prueba18: cadena, prueba19: cadena, prueba20 : String, test21: String, test22: String, test23: String,) -> Unit) {println(«Impresión no quiere llamarlo :sweat:»)}Vamos a descompilar… public final void insertEvent(@ NotNull FunctionN completeListener) {Intrinsics.checkNotNullParameter(completionListener, «completionListener»);String var2 = «Just Printing no quiere llamarlo :sweat:»;System.out.println(var2);}Wow, ahora hay algo llamado FunciónN. Te dejaré explorar qué es eso.