Und der Kotlin-Neuling fragt: "Warum wird der folgende Code nicht kompiliert?":
var left: Node? = null
fun show() {
if (left != null) {
queue.add(left) // ERROR HERE
}
}
Eine intelligente Umwandlung in "Knoten" ist nicht möglich, da "links" eine veränderbare Eigenschaft ist, die zu diesem Zeitpunkt möglicherweise geändert wurde
Ich verstehe , dass left
es sich um eine veränderbare Variable handelt, aber ich überprüfe dies explizit left != null
und bin left
vom Typ. Node
Warum kann sie nicht intelligent in diesen Typ umgewandelt werden?
Wie kann ich das elegant beheben? :) :)
n.left?.let { queue.add(it) }
Ich denke?Antworten:
Zwischen der Ausführung von
left != null
undqueue.add(left)
einem anderen Thread könnte sich der Wert vonleft
auf geändert habennull
.Um dies zu umgehen, haben Sie mehrere Möglichkeiten. Hier sind einige:
Verwenden Sie eine lokale Variable mit Smart Cast:
Verwenden Sie einen sicheren Anruf wie einen der folgenden:
Verwenden Sie den Elvis-Operator mit
return
, um frühzeitig von der umschließenden Funktion zurückzukehren:Beachten Sie, dass
break
undcontinue
in ähnlicher Weise für Überprüfungen innerhalb von Schleifen verwendet werden kann.quelle
Node
Klasse, die in der Originalversion der Frage definiert war und ein komplizierteres Code-Snippet enthieltn.left
anstelle von einfachleft
. Ich habe die Antwort entsprechend aktualisiert. Vielen Dank.val
für jede eine neue erstellenvar
, mehrere?.let
Anweisungen verschachteln oder?: return
je nach Ihrer Funktion mehrere Anweisungen verwenden. zBMyAsyncTask().execute(a1 ?: return, a2 ?: return, a3 ?: return)
. Sie können auch eine der Lösungen für eine "Mehrfachvariablen-Vermietung" ausprobieren. .1) Sie können auch verwenden,
lateinit
wenn Sie Ihre Initialisierung später oder anderswo sicher durchführenonCreate()
.Benutze das
An Stelle von
2) Und es gibt eine andere Möglichkeit, das
!!
Ende der Variablen zu verwenden, wenn Sie es so verwendenquelle
Zusätzlich zu denen in der Antwort von mfulton26 gibt es eine vierte Option.
Mit dem
?.
Operator können sowohl Methoden als auch Felder aufgerufen werden, ohnelet
lokale Variablen zu behandeln oder zu verwenden.Code für den Kontext:
Es funktioniert mit Methoden, Feldern und all den anderen Dingen, die ich versucht habe, damit es funktioniert.
Um das Problem zu lösen, können Sie
?.
die Methoden aufrufen , anstatt manuelle Umwandlungen oder lokale Variablen verwenden zu müssen.Als Referenz wurde dies in Kotlin getestet
1.1.4-3
, aber auch in1.1.51
und1.1.60
. Es gibt keine Garantie, dass es auf anderen Versionen funktioniert, es könnte eine neue Funktion sein.Die Verwendung des
?.
Operators kann in Ihrem Fall nicht verwendet werden, da es sich um eine übergebene Variable handelt, die das Problem darstellt. Der Elvis-Operator kann als Alternative verwendet werden und erfordert wahrscheinlich die geringste Menge an Code. Anstatt jedoch zu verwendencontinue
,return
könnte auch verwendet werden.Die Verwendung von manuellem Casting könnte ebenfalls eine Option sein, dies ist jedoch nicht null sicher:
Das heißt, wenn sich left in einem anderen Thread geändert hat , stürzt das Programm ab.
quelle
left
und nichtqueue
. Müssen Sie dies überprüfen, wird die Antwort in einer Minute bearbeitenDer praktische Grund, warum dies nicht funktioniert, hängt nicht mit Threads zusammen. Der Punkt ist, dass
node.left
effektiv in übersetzt wirdnode.getLeft()
.Dieser Eigenschafts-Getter kann wie folgt definiert werden:
Daher geben zwei Aufrufe möglicherweise nicht das gleiche Ergebnis zurück.
quelle
Wechseln Sie
var left: Node? = null
zulateinit var left: Node
. Problem gelöst.quelle
Mach das:
Dies scheint die erste Option zu sein, die die akzeptierte Antwort bietet, aber genau das suchen Sie.
quelle
Damit es eine intelligente Umwandlung der Eigenschaften gibt, muss der Datentyp der Eigenschaft die Klasse sein, die die Methode oder das Verhalten enthält, auf die Sie zugreifen möchten, und NICHT, dass die Eigenschaft vom Typ der Superklasse ist.
zB auf Android
Sein:
Lösung:
Verwendungszweck:
GL
quelle
Ihre eleganteste Lösung muss sein:
Dann müssen Sie keine neue und unnötige lokale Variable definieren, und Sie haben keine neuen Assertions oder Casts (die nicht DRY sind). Andere Bereichsfunktionen könnten ebenfalls funktionieren, wählen Sie also Ihren Favoriten.
quelle
Versuchen Sie es mit dem Nicht-Null-Assertionsoperator ...
quelle
Wie ich es schreiben würde:
quelle