2016-12-04 19 views
8

Mam następujący fragment kodu w Kotlin:Kotlin Char compareTo nie

val pair: Pair<Char,Char> = 'z' to 'z' 
val comparison = pair.first.compareTo(pair.second) 
println(comparison) 

To nie w drugiej linii z następującym wyjątkiem gdy próbuję go uruchomić:

java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number 

IDE (IntelliJ) nie narzeka na żaden niewłaściwy typ. Problem jest w jakiś sposób związany z faktem, że Chars pochodzą z Pair<Char, Char>, ponieważ 'z'.compareTo('z') działa dobrze. Czy wiesz, jak Kotlin rozwiązuje się po telefonie?

Używam Kotlin 1.0.4

Odpowiedz

10

TL; DR Najwyraźniej jest to błąd kompilatora.

Przyczyna tego zachowania leży w kodzie bajtowym generowanym przez kompilator Kotlin dla tych dwóch wywołań. (Jeśli używasz IntelliJ IDEA, możesz sprawdzić kod bajtowy za pomocą the bytecode viewing tool).

pierwsze, kod bajtowy generowane na wezwanie 'z'.compareTo('z') jest:

LINENUMBER 10 L3 
BIPUSH 122 
BIPUSH 122 
INVOKESTATIC kotlin/jvm/internal/Intrinsics.compare (II)I 

Apeluje kotlin.jvm.internal.Intrisics.compare() że porównuje dwa Int s, a Char s są wypychane do stosu bezpośrednio jako Int s (BIPUSH oznacza Push bajt jako liczba całkowita).

Ale jeśli spojrzeć na kod bajtowy dla pair.first.compareTo(pair.second) znajdziesz coś takiego:

ALOAD 1 
INVOKEVIRTUAL kotlin/Pair.getFirst()Ljava/lang/Object; 
CHECKCAST java/lang/Number 
INVOKEVIRTUAL java/lang/Number.intValue()I 

ALOAD 1 
INVOKEVIRTUAL kotlin/Pair.getSecond()Ljava/lang/Object; 
CHECKCAST java/lang/Number 
INVOKEVIRTUAL java/lang/Number.intValue()I 

INVOKESTATIC kotlin/jvm/internal/Intrinsics.compare (II)I 

Apeluje kotlin.jvm.internal.Intrisics.compare też, ale tutaj jest to, co próbuje zrobić przed:

  • Get komponent z pary (linie ALOAD 1 i INVOKEVIRTUAL ...)
  • Sprawdź, czy obiekt można obsadzić na Number (CHECKCAST ...)
  • Take java.lang.Number.intValue() (INVOKEVIRTUAL ...)

Drugie i trzecie linie są winowajcą, Char nie jest Number. Po prostu wygląda na to, że kompilator wygenerował niepoprawny kod bajtowy dla tego porównania (byłoby to poprawne dla typów Number, wydaje się, że Char nie jest obsługiwane osobno).

Istnieje an issue about this w narzędziu do śledzenia zagadek Kotlin, prawdopodobnie zostanie on rozwiązany w przyszłych wydaniach.


Aby naprawić połączenie w kodzie teraz można przekonwertować Char s ręcznie przed wywołaniem:

pair.first.toInt().compareTo(pair.second.toInt())