¿Cómo lidiar con una ambigüedad de resolución de sobrecarga de funciones con generics?

Considere esta class con dos funciones, una con el argumento Int , la otra con una genérica:

 class C<K, V> { // ... operator fun f(index: Int): Pair<K, V> = ... operator fun f(key: K): V = ... } 

Cuando se parametriza como C<Int, SomeType> , K es Int , y ambas funciones coinciden con las llamadas, lo que da como resultado un error:

 val m = C<Int, SomeType>() mf(1) 

Sobrecarga de ambigüedad de resolución. Todas estas funciones coinciden:

  • public final fun f(index: Int): SomeType definido en C
  • public final fun f(key: Int): Pair<Int, SomeType>? definido en C

¿Cómo puedo llamar a cualquiera que yo quiera en este caso?

Si tiene la suerte de tener diferentes nombres de parameters de las funciones, usar arguments con nombre hará el truco:

 mf(index = 1) // calls f(index: Int) mf(key = 1) // calls f(key: K) 

De lo contrario, si los nombres de los parameters son los mismos (o definidos en Java), una solución posible es realizar conversiones no verificadas para que el comstackdor elija la opción deseada:

  • Para llamar a f(index: Int) , puede usar

     @Suppress("UNCHECKED_CAST") val s = (m as C<*, SomeType>).f(1) as Pair<Int, SomeType> 

    La conversión a C<*, SomeType> hace que K sea ​​equivalente a in Nothing, out Any , lo que significa que no hay un argumento válido para f(key: K) , por lo que la llamada se resuelve naturalmente a f(index: Int) , pero necesita para devolver el resultado, porque de lo contrario es Pair<Any, SomeType> .

  • Para llamar a f(key: K) , use:

     @Suppress("UNCHECKED_CAST") val s = (m as C<Any, SomeType>).f(1 as Any) 

    De forma similar, el elenco de C<Any, SomeType> cambia la firma de la function deseada a f(key: Any) , y para llamarla, solo upcast 1 a Any .

Es lo mismo en el caso de varios parameters de tipo que chocan (p. Ej. f(key: K) y f(value: V) cuando K y V son ambos SomeType ), simplemente use arguments con nombre o el object para prohibir una de las funciones ( in Nothing ) o para hacer que acepte Any .

Kotlin stdlib usa la function de convención fun fAt(index: Int) para resolver tales casos.