Repare el tipo genérico al tipo del primer parámetro

Quiero escribir una function de extensión que estará disponible en cualquier tipo y aceptar parameters del mismo tipo o subtipo, pero no de un tipo completamente diferente.

Intenté un enfoque ingenuo pero no funcionó:

fun <T> Tf(x: T) { } fun main(args: Array<String>) { "1".f("1") // ok "1".f(1) // should be error } 

Parece que el comstackdor solo usa Any para T. Quiero que T se fije al tipo de receptor.

La única forma de hacerlo es decirle al comstackdor lo que quiere.

 fun <T> Tf(x: T) { } 

Para usarlo, debes decirle a Kotlin cuál es el tipo que quieres que sea.

 "1".f<String>("2") // Okay "1".f(2) // Okay (see voddan's answer for a good explanation) "1".f<String>(2) // Fails because 2 isn't a String "1".f<Int>(2) // Fails because "1" isn't an Int 

Cuando llama a fun <T> Tf(x: T) {} como "1".f(1) , el comstackdor busca un super-tipo común de String e Int , que es Any . Luego decide que T is Any y no emite ningún error. La única forma de influir en este process es especificar T explícitamente: "1".f<String>(1)

Como todas las comprobaciones son realizadas por el comstackdor, el problema no tiene nada que ver con el borrado de types.

Su problema es como decir " John es 3 años mayor que Carl, y Carl es 3 años más joven que John " … todavía no conoce sus edades sin más información. Ese es el tipo de evidencia que le dio al comstackdor y luego esperaba que adivinara correctamente. La única verdad que puede get de esa información es que John tiene al less 3 años y Carl tiene al less 1 día.

Y este tipo de suposition es como el comstackdor que encuentra los límites superiores comunes de Any . Tenía dos types literales fuertes para elegir y ninguna posibilidad de variar tampoco. ¿Cómo decidiría si el Int o String es más importante, y al mismo time le dijiste que cualquier T con los límites superiores de Any? fue válido dada su especificación de tipo. Entonces, la respuesta segura es ver si ambos literales pueden cumplir los criterios de T: Any? y por supuesto que sí, ambos tienen antepasados ​​de Any . El comstackdor cumplió con todos sus criterios, incluso si no lo deseaba.

Si tuvieras criterios de desempate, esto funcionaría de manera diferente. Por ejemplo, si tiene un tipo de devolución de T y una variable de tipo String recibe el valor, eso influiría en la decisión de Inferencia de tipo. Esto, por ejemplo, produce un error:

 fun <T: Any> T.f2(x: T): T = x val something: String = "1".f2(1) // ERROR 

Porque ahora el tipo T está anclado por el "lado izquierdo" de la expresión que espera String sin ninguna duda.

También existe la posibilidad de que esto también pueda ser un problema de inferencia de tipo que no está previsto, verifique los problemas informados en YouTrack o agregue los suyos propios para get una respuesta definitiva del equipo del comstackdor. Agregué una request de function como KT-13138 para anclar un parámetro de tipo específico para ver cómo responde el equipo.

Puede fijar T al tipo de receptor haciendo f una propiedad de extensión que devuelve un object invocable:

 val <T> Tf: (T) -> Unit get() = { x -> } fun main(vararg args: String) { "1".f("1") // will be OK once KT-10364 is resolved "1".f(1) // error: The integer literal does not conform to the expected type String } 

Desafortunadamente, "1".f("1") causa actualmente un error: "Tipo no coincidente: el tipo inferido es Cadena pero se esperaba T". Este es un problema de comstackdor. Ver KT-10364 . Ver también KT-13139 . Puede votar y / o mirar los problemas para las actualizaciones. Hasta que esto se solucione, puede hacer lo siguiente:

 "1".f.invoke("1") /* or */ ("1".f)("1") /* or */ val f = "1".f f("1") 
  • Crear una instancia de un oyente de interfaz en Kotlin
  • Cómo usar con envoltorios pnetworkingeterminados?
  • La animation SwipeRefreshLayout del primer bash de actualización se ejecuta sin parar
  • Dividir algorithm y ver parte usando un Patrón de estrategia en Kotlin
  • Anulación de getter de Kotlin + MongoDB
  • ¿Debo cancelar la suscripción cuando uso rxbinding?
  • ¿Cómo acceder a Mono <T> mientras se maneja la exception con onErrorMap ()?
  • Mocking methods de Kotlin con Java + Mockito
  • Kotlin - Sobrecarga del operador de invocación de la function
  • Kotlin - Agregar elementos a ExpandableListView
  • Serializable en Kotlin