2016-11-21 3 views
5

diese Klasse mit zwei Funktionen Betrachten, eines mit Int Argument, das andere mit einem generischen:Wie behandelt man eine Mehrdeutigkeitsauflösung von Funktionen mit Generics?

class C<K, V> { 
    // ... 

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

Wenn es als C<Int, SomeType> parametriert, K ist Int, und beide Funktionen die Anrufe entsprechen, einem Fehler führt in :

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

Overload resolution ambiguity. All these functions match:

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

Wie rufe ich je nachdem, was f ich in diesem Fall wollen?

Antwort

7

Wenn Sie Glück haben genug, um verschiedene Parameter Namen der Funktionen zu haben, named arguments mit dem Trick:

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

Andernfalls, wenn die Parameternamen identisch sind (oder in Java definiert), einen mögliche Abhilfe ist unchecked casts durchzuführen, um den Compiler, um die gewünschte Option zu wählen:

  • f(index: Int) aufrufen, können Sie

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

    Die Besetzung zu C<*, SomeType>makes K equivalent to in Nothing, out Any, was bedeutet, dass es für f(key: K), so wird der Anruf natürlich gelöst f(index: Int), aber Sie müssen werfen das Ergebnis zurück, sonst kein gültiges Argument ist, weil es Pair<Any, SomeType> ist.

  • f(key: K) aufzurufen, verwenden:

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

    Auch die Besetzung zu C<Any, SomeType> die Signatur der gewünschten Funktion zu f(key: Any) ändert, und es zu nennen, nur upcast 1-Any.

Es ist alles das Gleiche bei mehreren Typparametern clashing (zB f(key: K) und f(value: V) wenn K und V sind beide SomeType), nur benannte Argumente verwenden oder um das Objekt zu Verbot eine der Funktionen werfen (in Nothing) oder um es zu akzeptieren Any.

0

Kotlin stdlib verwendet die Konvention fun fAt(index: Int), um solche Fälle zu lösen.

+1

Das stimmt, aber das erfordert im Voraus einige Überlegungen, um die Klasse 'C' zu entwerfen, die mögliche Signaturkonflikte mit substituierten Generika verhindert. Und wenn Sie einer solchen Klasse gegenüberstehen und keine Möglichkeit haben, ihre Funktionen umzubenennen, müssen Sie auf generische Tricks aus der Antwort von @ hotkey zurückgreifen. – Ilya

Verwandte Themen