Funciones de alto orden de Kotlin, puedes aprender después de leer

prefacio

Hoy hablaremos de las expresiones lambda. Las expresiones lambda deberían ser familiares para todos.. Se introdujo una característica muy importante en Java8, que libera a los desarrolladores de la engorrosa sintaxis original, pero está limitada solo a la versión Java8. Kotlin compensa este problema. La programación mixta de expresiones lambda y Java en Kotlin puede admitir versiones anteriores a Java8.

Por qué usar expresiones Lambda en Kotlin

Respecto al problema de utilizar expresiones lambda en Kotlin, existen principalmente las siguientes ventajas:

  • La expresión lambda de Kotlin tiene una sintaxis más concisa y fácil de entender para realizar funciones, lo que libera a los desarrolladores de la declaración de sintaxis redundante y prolija original. Puede usar operadores de programación funcional como filtrado, mapeo y conversión para procesar datos de recopilación, de modo que su código se acerque más al estilo de programación funcional.
  • Las versiones anteriores a Java 8 no admiten expresiones lambda, mientras que Kotlin es compatible con versiones anteriores a Java 8 y tiene una buena interoperabilidad. Es muy adecuado para el modelo de desarrollo mixto de versiones anteriores a Java 8 y Kotlin. Resuelve el cuello de botella que las versiones anteriores a Java 8 no puede usar expresiones lambda.
  • El uso de expresiones lambda en la versión Java8 es limitado, no es un cierre en el verdadero sentido, y la lambda en Kotlin es la implementación que admite los cierres en el verdadero sentido. (explicado a continuación)

Las funciones de Kotlin son funciones de primera clase, lo que significa que pueden almacenarse en variables y estructuras de datos, pasarse como argumentos y devolverse desde otras funciones de orden superior. Para otros valores que no son funciones, puede operar en funciones de cualquier forma posible.

Para lograr esto, como lenguaje de programación tipificado estáticamente, Kotlin usa una serie de tipos de funciones para representar funciones y proporciona un conjunto de construcciones de lenguaje especializadas, como expresiones lambda.

1. Funciones de orden superior

Una función de orden superior es aquella que toma una función como argumento (o devuelve una función) . Es decir, una función puede tomar otra función como parámetro (o función de retorno), y una función que utiliza otras funciones como parámetros (o función de retorno) se denomina "función de orden superior".

(1) El siguiente es un ejemplo de una función de orden superior:

fun stringMapper(str: String, mapper: (String) -> Int): Int {
    // Invoke function
    return mapper(str)
}

stringMapper()Los parámetros de la función son a Stringy una función que Stringderivará Intel valor la que le pasas.

Para llamar a stringMapper(), puedes pasar una Stringy una función que satisfaga las condiciones del segundo parámetro (es decir, una función que Stringtoma como entrada y Intsalida ), como en el siguiente ejemplo:

stringMapper("Android", { input ->
    input.length
})

Si la función anónima es el último parámetro definido en una función, puede pasar este parámetro ()fuera de , de la siguiente manera:

stringMapper("Android") { input ->
    input.length
}

(2) Otro buen ejemplo es el modismo de programación funcional , que toma un valor acumulador inicial y una función de composición, y lo calcula combinando sucesivamente el valor acumulador actual con cada elemento de la colección Construye su valor de retorno, reemplazando esta superposición:

//从[初始]值开始累加值,从左到右对当前累加器值和每个元素应用[操作]
fun <T, R> Collection<T>.fold(
    initial: R,
    combine: (acc: R, nextElement: T) -> R
): R {
    var accumulator = initial
    for (element: T in this) {
        accumulator = combine(accumulator, element)
    }
    return accumulator
}

En el código anterior, el parámetro combinetiene un tipo de función (R, T) -> R, por lo que recibe una función que toma dos parámetros de tipo Ry Ty devuelve un valor Rde . Se llama en un bucle for y luego asigna el valor devuelto a accumulator.

call fold, debemos pasarle una instancia del tipo de función como argumento, y las expresiones lambda (descritas con más detalle a continuación) se usan ampliamente en este caso en sitios de llamadas a funciones de orden superior:

val items = arrayOf(1, 2, 3, 4, 5)
//Lambdas是大括号括起来的代码块
items.fold(0, { acc: Int, i: Int -> //当lambda 有参数时,参数在前面,然后是 `->` 符号
    print("acc == $acc | i == $i | ")
    val result = acc + i
    println("result == $result")
    //如果不显式指定,lambda 中的最后一个表达式被认定为是返回值
    result
})

//参数类型在lambda中如果能自动推断则可以省略
val itemsStr = items.fold("Elements:", { acc, i -> acc + "" + i })

//函数引用也可以用于高阶函数调用
val products = items.fold(1, Int::times)

Los datos de impresión son los siguientes:

acc == 0 | i == 1 | result == 1
acc == 1 | i == 2 | result == 3
acc == 3 | i == 3 | result == 6
acc == 6 | i == 4 | result == 10
acc == 10 | i == 5 | result == 15

1.1 Tipo de función

Kotlin usa una serie de tipos de funciones, como (Int) -> Stringpara declarar funciones: val onClick: () -> Unit = .... Estos tipos tienen una notación especial correspondiente a la firma de funciones, es decir, sus parámetros y valor de retorno:

  • (A, B) -> C: Todos los tipos de funciones tienen una lista de tipos de parámetros entre paréntesis y un tipo de devolución. (A, B) -> CRepresenta un tipo de función que representa una función que toma dos parámetros de tipo A y B y devuelve un valor de tipo C. La lista de tipos de parámetros puede estar vacía, p () -> A. UnitEl tipo de devolución no se puede omitir ;
  • A.(B) -> C: un tipo de función puede tener un tipo de receptor adicional, que se especifica .antes . Tipo A.(B) -> CIndica que el parámetro de tipo B se puede llamar en el objeto receptor A, y el valor de retorno es una función de tipo C. Los literales de función con receptores a menudo se usan con estos tipos;
  • Función de suspensión: una función del tipo de atributo de atributo de función de suspensión tiene un modificador de suspensión en la notación. Por ejemplo: suspend () -> Unito suspend A.(B) -> C.

La notación del tipo de función puede incluir opcionalmente los nombres de los parámetros de la función: (x: Int, y: Int) -> Point. Estos nombres se pueden utilizar para documentar el significado de los parámetros.

1. Para especificar que un tipo de función puede estar vacío, puede usar paréntesis:((Int, Int) -> Int)?

2. Los tipos de funciones se pueden combinar usando paréntesis:(Int) -> ((Int) -> Unit)

3. El símbolo de flecha ->es asociativo a la derecha (Int) -> (Int) -> Unity (Int) -> ((Int) -> Unit)representa el mismo tipo que , pero ((Int) -> (Int)) -> Unites diferente del tipo de función .

También puede usar alias de tipo para dar a un tipo de función un nombre alternativo:

typealias ClickHandler = (Button, ClickEvent) -> Unit

1.2 Tipo de función de instanciación

Hay varias formas de obtener una instancia de un tipo de función:

(1) Use bloques de código en literales de funciones de la siguiente forma:

  • Una expresión lambda: { a, b -> a + b };
  • Una función anónima: fun(s: String): Int { return s.toIntOrNull() ?: 0 }.

Un literal de función con receptor se puede utilizar como valor de un tipo de función con receptor.

(2) Use una instancia de una clase personalizada que implemente el tipo de función como una interfaz:

//定义IntTransformer类型,实现了 (Int) -> Int 接口
class IntTransformer : (Int) -> Int {
    override operator fun invoke(num: Int): Int = TODO()
}

val intFunction: (Int) -> Int = IntTransformer()

Si los datos son lo suficientemente inequívocos, el compilador puede inferir el tipo de función de la variable:

val result = { i: Int -> i * 2 }//推断出的类型是(Int) -> Int

Para un tipo de método que contiene un receptor, si el tipo del receptor y los tipos de parámetros restantes del tipo de método coinciden con los parámetros de entrada del tipo de método que no define explícitamente al receptor, los dos pueden realizar una asignación mutua . Por ejemplo, un tipo de método String.(Int) -> Booleanes un tipo de método que contiene explícitamente un receptor. El tipo de método del receptor es Stringy el tipo de parámetro es Int, por lo que es equivalente al tipo de método. (String, Int) -> BooleanEste tipo de método recibe un Stringtipo y un Intparámetro de tipo, y el primer Stringtipo solo coincide con el receptor, los tipos de parámetros restantes también coinciden entre sí y pueden considerarse iguales.

//String,Int传入的参数类型后面的String表示返回值类型,times表示Int类型参数
val substringStr: String.(Int) -> String = { times ->
    this.substring(0, times)//times为5
}

val twoParameters: (String, Int) -> String = substringStr

//(A, B) -> C 所有的函数类型有一个带括号的参数类型列表和一个返回类型,
//表示一个类型,该类型表示具有类型 A 和 B 的两个参数并返回类型 C 的值的函数。
fun runTransformation(ss: (String, Int) -> String): String {
    return ss("Android", 5)
}

val trans = runTransformation(substringStr) //substringStr()函数作为参数传递给runTransformation()函数

Los datos de impresión son los siguientes:

Andro

Nota: El tipo de una función sin receptor se deduce automáticamente de forma predeterminada, incluso si la variable se inicializa con una referencia a la función de extensión. Si desea cambiarlo, especifique el tipo de variable explícitamente.

1.3 Instancia de tipo de función de llamada

Un valor de un tipo de función se puede invocar utilizando su invoke(...)operador : f.invoke(x)o f(x). invoke()Representa 函数变量llamarse .

Si el valor tiene un tipo de receptor, se debe pasar un objeto receptor como primer parámetro. Otra forma de llamar a un valor de tipo función con un receptor es ponerle el prefijo del objeto receptor, como si el valor fuera una función de extensión: 1.foo(2).

//String.plus()通过将该字符串与给定的其他对象的字符串表示形式链接起来而获得的字符串
val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus //Int.plus()将另一个值添加到此值

val str = stringPlus.invoke("<-", "->") //打印:<-->
val str2 = stringPlus("Hello", "World") //打印:HelloWorld

val int1 = intPlus(1, 1) //打印:2
val int2 = intPlus.invoke(2, 3) //打印:5
val int3 = 4.intPlus(5) //打印:9

Este artículo está en el proyecto de código abierto: ¿ El desarrollo de Android no sabe esto? Se ha incluido Cómo conseguir un sueldo alto en una entrevista , que contiene rutas de programación de autoaprendizaje en diferentes sentidos, recogida de preguntas de entrevista/presencial, y una serie de artículos técnicos, etc. Escanea el siguiente código QR para recibir gratis. Los recursos se actualizan continuamente...

Supongo que te gusta

Origin blog.csdn.net/Eqiqi/article/details/129875836
Recomendado
Clasificación