¿Cuál es el uso del parámetro de tipo <T> antes del nombre de la función en Kotlin?
Ejemplo:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] this[index1] = this[index2] this[index2] = tmp } Haciendo referencia a la primera <T> anterior.
Intenté revisar los documentos de Kotlin con respecto a los genéricos, así como los genéricos de Java , sin embargo, en su mayoría solo tocan el segundo <T> , no el primero.
Se utiliza para indicar que se utilizan genéricos y no se referencia algún tipo T
Echa un vistazo a este ejemplo completamente válido
fun <String> MutableList<String>.swap(index1: Int, index2: Int) Ahora esto se puede llamar en cualquier MutableList<*> y no solo MutableList<String> . Si no escribieras <String> después de la palabra clave fun , ¿cómo sabría kotlin que, de hecho, te estás refiriendo a un genérico y no a kotlin.String ?
Lo mismo ocurre con el ejemplo que has mostrado. El <> después de la fun simplemente introduce un nuevo parámetro genérico, de lo contrario, Kotlin se quejaría de que no conocería el tipo T
(Aquí hay otro enfoque.)
Considere una función normal, no genérica:
fun myFun(a: Int, b: String) { // …use a and b… } ¿Qué son a y b ? Todavía no significan nada. Simplemente están diciendo 'Cuando llamas a esta función, debes pasar estos valores'. Es de esperar que el cuerpo de la función se refiera a ellos de alguna manera; ahí es cuando se acostumbran.
Ahora considere una función genérica:
fun <T, U> myFun(/* …use T and U… */) { // … } Es lo mismo con T y U Esos también son parámetros: parámetros de tipo . Al igual que con los parámetros de valor, la declaración de parámetros de tipo no significa nada en sí misma, pero brinda marcadores de posición para los tipos que se deben pasar (explícitamente o inferir) al llamar a la función. (La declaración <…> también brinda un lugar para especificar cualquier restricción o variación, por ejemplo, <T : Number> o <out T> ). Y normalmente usaría esos parámetros de tipo más adelante, en este caso, en el resto de la firma de la función.
Para agregar a la respuesta de Lino, imagine que esta definición tiene llaves invisibles después de la declaración del parámetro de tipo:
fun <T> \*{*\ MutableList<T>.swap(index1: Int, index2: Int) {...} \*}*\ Por lo tanto, tiene un alcance léxico adecuado. Si esa <T> fuera después del nombre de la función, perdería esta propiedad, complicaría el analizador y solo haría que el código fuera menos legible para los humanos.
También sería difícil recordar poner <T> antes del nombre para las funciones de extensión, pero después para las funciones miembro. ¡Ya es bastante malo que tenga que hacerse para las clases!
Scala pone [T] después del nombre del método, pero eso se debe a que tiene una sintaxis muy diferente para la función correspondiente a los métodos de extensión. Scala 3 optará por el complicado enfoque del analizador , probablemente porque la sintaxis similar a la de Kotlin no encajaría con ninguna otra sintaxis.