Wie kann ich in Kotlin nach generischen Typen suchen?


79

Ich versuche in Kotlin nach einem generischen Typ zu suchen.

if (value is Map<String, Any>) { ... }

Aber der Compiler beschwert sich bei

Beispiel für gelöschten Typ kann nicht überprüft werden: jet.Map

Die Prüfung mit einem normalen Typ funktioniert gut.

if (value is String) { ... }

Kotlin 0.4.68 wird verwendet.

Was fehlt mir hier?

Antworten:


91

Das Problem ist, dass Typargumente gelöscht werden, sodass Sie nicht mit der vollständigen Typzuordnung vergleichen können, da zur Laufzeit keine Informationen zu diesen Zeichenfolgen und Beliebigen vorhanden sind.

Verwenden Sie Platzhalter, um dies zu umgehen:

if (value is Map<*, *>) {...}

Toll! Das funktioniert perfekt! Das Beispiel in der Dokumentation hat mich gerade verwirrt: Confluence.jetbrains.net/display/Kotlin/Type+casts
Philipp Brüll

49
Was ist, wenn Sie tatsächlich überprüfen möchten, ob etwas ein Collection<String>automatisches Casting ist?
Berühmte

Ich habe so einen Ausschnitt if (it.getSerializable(ARG_PARAMS) is HashMap<*, *>) {it.getSerializable(ARG_PARAMS) as HashMap<String, String>} else null. Im Grunde wird es versuchen zu besetzen HashMap<String, Integer>, HashMap<String, String>wenn ich gegen generischen Typ prüfe. Vermisse ich etwas
Farid

@FARID Ja, das wird es, und diese Art der Besetzung ist nicht sicher
Andrey Breslav

16

JVM entfernt die generischen Typinformationen. Aber Kotlin hat Generika verdichtet. Wenn Sie einen generischen Typ T haben, können Sie den Typparameter T einer Inline-Funktion als bestätigt markieren, damit sie zur Laufzeit überprüft werden kann.

So können Sie tun:

inline fun <reified T> checkType(obj: Object, contract: T) {
  if (obj is T) {
    // object implements the contract type T
  }
}

1
Können Sie ein Beispiel für einen Anruf zeigen checkType()? Ich bin mir nicht sicher, was ich für das zweite Argument tun soll.
Michael Osofsky

9

Ich denke, das ist angemessener

inline fun <reified T> tryCast(instance: Any?, block: T.() -> Unit) {
    if (instance is T) {
        block(instance)
    }
}

Verwendung

// myVar is nullable
tryCast<MyType>(myVar) {
    // todo with this e.g.
    this.canDoSomething()
}

Ein weiterer kürzerer Ansatz

inline fun <reified T> Any?.tryCast(block: T.() -> Unit) {
    if (this is T) {
        block()
    }
}

Verwendung

// myVar is nullable
myVar.tryCast<MyType> {
    // todo with this e.g.
    this.canDoSomething()
}

Warum so etwas nicht direkt in kotlin stdlib verfügbar ist :-(
ATom

Ist nicht something as? String dasselbe? Beachten Sie das Fragezeichen nach as?
Dalibor Filus
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.