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?

Philipp Brüll
quelle

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<*, *>) {...}
Andrey Breslav
quelle
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
  }
}
menno
quelle
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()
}
Vlad
quelle
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