type reified parameter objects functions example enum cast generics kotlin

generics - reified - kotlin parameter



¿Cómo puedo restringir un parámetro de función de extensión de Kotlin para que sea el mismo que el tipo extendido? (3)

Quiero escribir un método de extensión en un tipo genérico T, donde el tipo coincidente restringe un parámetro de método.

Quiero que esto compile:

"Hello".thing("world")

Pero no esto, ya que 42 no es una cadena:

"Hello".thing(42)

Esta definición no funciona, porque T cumple con T

fun <T> T.thing(p: T) {}


Como lo mencionó @Alexander Udalov , no es posible hacerlo directamente, pero existe una solución alternativa en la que se define el método de extensión en otro tipo, por lo que:

data class Wrapper<T>(val value: T) val <T> T.ext: Wrapper<T> get() = Wrapper(this) fun <T> Wrapper<T>.thing(p: T) { println("value = $value, param = $p") }

Con lo anterior se compila lo siguiente:

"abc".ext.thing("A")

pero el siguiente falla

"abc".ext.thing(2)

con:

Kotlin: Type inference failed: Cannot infer type parameter T in fun <T> Wrapper<T>.thing(p: T): Unit None of the following substitutions receiver: Wrapper<String> arguments: (String) receiver: Wrapper<Int> arguments: (Int) can be applied to receiver: Wrapper<String> arguments: (Int)

Según lo sugerido por @hotkey, parece que debería ser posible evitar la necesidad del tipo Wrapper explícito con la siguiente propiedad de extensión:

val <T> T.thing: (T) -> Any? get() = { println("extension body") }

Y luego "abc".thing("A") como "abc".thing("A") pero también falla . Sorprendentemente, lo siguiente compila "abc".thing.invoke("A")


Mejorar la solución de @miensol y hacerla visualmente idéntica a la llamada de función:

val <T> T.foo: (T) -> SomeType get() = { other -> ... }

Esta es una propiedad de extensión que proporciona un lambda, que puede invocarse inmediatamente con un argumento del mismo tipo T como este:

"abc".foo(1) // Fail "abc".foo("def") // OK

Desafortunadamente, youtrack.jetbrains.com/issue/KT-13965 que le impide escribir "abc".thing("abc") , pero cualquiera de "abc".thing.invoke("abc") y ("abc".thing)("abc) funciona bien y filtra las llamadas sin cadenas.


Que yo sepa, esto no es posible en Kotlin 1.0. Hay varios problemas en el rastreador ( first , second ) sobre un caso de uso similar, y la solución propuesta en el primero probablemente también ayude aquí en el futuro.