studio library framework commons async kotlin

library - ¿Qué significa una firma de función de Kotlin con T.()?



kotlin anko toast (2)

Este es otro concepto sorprendente llamado Función literales con receptor. Se parece a la función de extensión con la diferencia de que tiene "receiver" .

inline fun doSomethingWithInt(receiver: Int.() -> Unit) { 5.receiver() //Possible as receiver is Int type receiver(5) //possible as receiver should be passed as first Argument }

Vamos a romper esto

(receiver: Int.() -> Unit)

En qué se diferencia esto de Regular lambda como () -> Unit es que tiene un receptor que es Tipo de Int

Tan similar a la función de extensión, este receptor puede invocar en el tipo Int.

5.receiver()

Y según la documentación aquí.

Se puede invocar un valor de un tipo de función utilizando su operador de invocación (...):

f.invoke (x) o simplemente f (x).

Si el valor tiene un tipo de receptor, el objeto del receptor se debe pasar como el primer argumento . Otra forma de invocar un valor de un tipo de función con receptor es anteponerlo con el objeto receptor, como si el valor fuera una función de extensión: 1.foo (2)

Así que también puedes escribir receiver(5)

Ahora podemos escribir código de estilo DSL debido a esto. Vamos a ver la función de biblioteca estándar de kotlin Apply

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

Como puede ver, aplicar es una función de extensión de T, el bloque funcionará con el receptor tipo T ,

Debido a T. () T estará disponible como primer argumento en lambda.

Ahora aquí el bloque es invocado por bloque () dentro del cuerpo de la función, pero también puede escribir this.block () o bloque (this)

Y después de invocar este lambda , devolveremos una instancia de T (se llama a la misma instancia en la que se aplica)

Entonces, lo que hicimos en aplicar es tomar lambda en el argumento, ejecutarlo en la misma instancia T en la que fue llamado y devolver la misma instancia T

Ejemplo

La llamada de esta función se verá así:

(StringBuilder("Hello ").apply({ append("Kotliner") }))

Pero en kotlin si lambda es el último argumento, en lugar de escribir como funName({}) , simplemente puede escribir funName{} .

así que el código anterior también se puede escribir como

StringBuilder("Hello ").apply { append("Kotliner") append("! ") }

Lo que parece más claro y conciso. De esta manera, Kotlin proporciona una estructura DSL como Groovy.

Este es un muy buen blog sobre el mismo tema.

Esta es una función estándar de Kotlin (que yo sepa)

inline fun<T> with(t: T, body: T.() -> Unit) { t.body() }

Pero, ¿podría alguien escribir en inglés simple lo que significa exactamente la firma? Es una función genérica para T, con el primer argumento "t" de tipo T y el segundo, "cuerpo" del tipo de función, aceptando una función de ???? y devolviendo nada (unidad)

Veo esta notación Algo. () -> Algo se usa con bastante frecuencia, es decir, para Anko:

inline fun Activity.coordinatorLayout(init: CoordinatorLayout.() -> Unit) = ankoView({ CoordinatorLayout(it) },init)

pero no creo que se haya explicado en ninguna parte lo que () significa ...


T.() -> Unit es un tipo de función de extensión con receptor.

Además de las funciones ordinarias, Kotlin soporta funciones de extensión. Dicha función difiere de una ordinaria en que tiene una especificación de tipo de receptor. Aquí es una parte genérica de T.

La palabra clave this dentro de una función de extensión corresponde al objeto receptor (el que se pasa antes del punto), por lo que puede llamar sus métodos directamente (haciendo referencia a this desde los ámbitos primarios aún es posible con los calificadores ).


La función with es una estándar, sí. Es el código actual:

/** * Calls the specified function [f] with the given [receiver] as its receiver and returns its result. */ public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()

Así que es una función genérica para T y R , con el primer argumento "receptor" de tipo T y segundo, f de tipo de función de extensión, que extiende T , devolviendo el tipo R que a su vez devolvió with .

Por ejemplo, puedes usarlo así:

val threadInfoString = with (Thread.currentThread()) { // isDaemon() & getPriority() are called with new property syntax for getters & setters "${getName()}[isDaemon=$isDaemon,priority=$priority]" }


Vea la documentación para las funciones de extensión aquí:
kotlinlang.org/docs/reference/lambdas.html#extension-function-expressions
kotlinlang.org/docs/reference/extensions.html

Adicional:

Entonces, ¿la única f válida sería cualquier función de argumento 0 definida para T?

Realmente no. En Kotlin , los tipos de función y los tipos de función de extensión están unificados , de modo que se pueden usar de manera intercambiable. Por ejemplo, podemos pasar String :: length donde se espera una función (String) -> Int .

// map() expects `(String) -> Int` // argument has type `String.() -> Int` strings.map(String::length)

Los tipos como Thread.() -> String & (Thread) -> String son los mismos desde el lado de fondo; de hecho, el receptor es el primer argumento.

Por lo tanto, cualquiera de las siguientes funciones es adecuada para Thread.() -> String Argumento de Thread.() -> String :

fun main(args: Array<String>) { val f1 = fun Thread.(): String = name val f2 = fun Thread.() = name val f3: Thread.() -> String = { name } val f4: (Thread) -> String = { it.name } val f5 = { t: Thread -> t.name } val f6: (Thread) -> String = Thread::getNameZ val f7: Thread.() -> String = Thread::getNameZ val f8 = Thread::getNameZ } fun Thread.getNameZ() = name

O simplemente puede usar la función literal ( {} ) como en el ejemplo con threadInfoString , pero funciona solo cuando el tipo de receptor se puede inferir del contexto.