Et le novice Kotlin demande: "Pourquoi le code suivant ne se compile-t-il pas?":
var left: Node? = null
fun show() {
if (left != null) {
queue.add(left) // ERROR HERE
}
}
La conversion intelligente vers 'Node' est impossible, car 'left' est un mutable propriété qui aurait pu être changée à ce moment
J'obtiens que left
est une variable mutable, mais je vérifie explicitement left != null
et left
est de type Node
alors pourquoi ne peut-il pas être intelligemment configuré pour ce type?
Comment puis-je résoudre ce problème avec élégance? :)
Entre l'exécution de left != null
et queue.add(left)
, un autre thread aurait pu remplacer la valeur de left
par null
.
Pour contourner ce problème, vous avez plusieurs options. Voilà quelque:
Utilisez une variable locale avec smart cast:
val node = left
if (node != null) {
queue.add(node)
}
Utilisez un appel sûr tel que l’un des suivants:
left?.let { node -> queue.add(node) }
left?.let { queue.add(it) }
left?.let(queue::add)
Utilisez l'opérateur Elvis avec return
pour revenir plus tôt à partir de la fonction englobante:
queue.add(left ?: return)
Notez que break
et continue
peuvent être utilisés de la même manière pour les vérifications au sein de boucles.
Il existe une quatrième option en plus de celles de la réponse de mfulton26.
En utilisant l'opérateur ?.
, il est possible d'appeler des méthodes ainsi que des champs sans utiliser let
ni utiliser des variables locales.
Un code pour le contexte:
var factory: ServerSocketFactory = SSLServerSocketFactory.getDefault();
socket = factory.createServerSocket(port)
socket.close()//smartcast impossible
socket?.close()//Smartcast possible. And works when called
Cela fonctionne avec les méthodes, les champs et toutes les autres choses que j'ai essayé de faire fonctionner.
Ainsi, pour résoudre le problème, vous pouvez utiliser ?.
pour appeler les méthodes au lieu d'utiliser des conversions manuelles ou des variables locales.
Pour référence, cela a été testé dans Kotlin 1.1.4-3
, mais également dans 1.1.51
et 1.1.60
. Il n'y a aucune garantie que cela fonctionne sur d'autres versions, cela pourrait être une nouvelle fonctionnalité.
L'utilisation de l'opérateur ?.
ne peut pas être utilisée dans votre cas car c'est une variable passée qui pose problème. L'opérateur Elvis peut être utilisé comme alternative, et c'est probablement celui qui nécessite le moins de code. Au lieu d'utiliser continue
cependant, return
pourrait également être utilisé.
L'utilisation de la diffusion manuelle peut également être une option, mais ceci n'est pas null safe:
queue.add(left as Node);
Signification si laissé a changé sur un autre thread, le programme va planter.
Vous pouvez également utiliser lateinit
Si vous effectuez votre initialisation ultérieurement à onCreate()
ou ailleurs.
Changement
var left: Node? = null
À
lateinit var left: Node
La raison pratique pour laquelle cela ne fonctionne pas n'est pas liée aux threads. Le fait est que node.left
est effectivement traduit en node.getLeft()
.
Ce getter de propriété peut être défini comme:
val left get() = if (Math.random() < 0.5) null else leftPtr
Par conséquent, deux appels peuvent ne pas renvoyer le même résultat.
Essayez d'utiliser l'opérateur d'assertion non nul ...
queue.add (à gauche !!)
Faire ceci:
var left: Node? = null
fun show() {
val left = left
if (left != null) {
queue.add(left) // safe cast succeeds
}
}
Ce qui semble être la première option fournie par la réponse acceptée, mais c'est ce que vous recherchez.