Il cast intelligente su “Tipo” è imansible, perché “variabile” è una proprietà mutabile che potrebbe essere stata modificata in questo momento

E il novellino di Kotlin chiede “perché il seguente codice non verrà compilato?”:

var left: Node? = null fun show() { if (left != null) { queue.add(left) // ERROR HERE } } 

Il cast intelligente su “Node” è imansible, perché “left” è una proprietà mutabile che potrebbe essere stata modificata in questo momento

La left è variabile mutabile, ma sto verificando esplicitamente left != null e left è di tipo Node quindi perché non può essere convertito in smart in quel tipo?

Come posso risolvere questo elegantemente? 🙂

Tra l’esecuzione di left != null e queue.add(left) un altro thread avrebbe potuto modificare il valore di left a null .

Per ovviare a questo hai diverse opzioni. Eccotene alcune:

  1. Usa una variabile locale con il cast intelligente:

     val node = left if (node != null) { queue.add(node) } 
  2. Utilizzare una chiamata sicura come una delle seguenti:

     left?.let { node -> queue.add(node) } left?.let { queue.add(it) } left?.let(queue::add) 
  3. Utilizzare l’ operatore Elvis con return per tornare presto dalla funzione di chiusura:

     queue.add(left ?: return) 

    Si noti che break e continue possono essere utilizzati in modo simile per i controlli all’interno di loop.

C’è una quarta opzione in aggiunta a quella nella risposta di mfulton26.

Usando il ?. operatore è ansible chiamare metodi e campi senza occuparsi di let o utilizzare variabili locali.

Qualche codice per il contesto:

 var factory: ServerSocketFactory = SSLServerSocketFactory.getDefault(); socket = factory.createServerSocket(port) socket.close()//smartcast impossible socket?.close()//Smartcast possible. And works when called 

Funziona con metodi, campi e tutte le altre cose che ho provato a farlo funzionare.

Quindi per risolvere il problema, invece di dover usare cast manuali o usare variabili locali, puoi usare ?. chiamare i metodi.

Per riferimento, questo è stato testato in Kotlin 1.1.4-3 , ma anche testato in 1.1.51 e 1.1.60 . Non c’è alcuna garanzia che funzioni su altre versioni, potrebbe essere una nuova funzionalità.

Usando il ?. l’operatore non può essere utilizzato nel tuo caso dal momento che è una variabile passata che è il problema. L’operatore Elvis può essere utilizzato come alternativa ed è probabilmente quello che richiede la minor quantità di codice. Invece di usare continue , è ansible utilizzare anche return .

Anche l’utilizzo della fusione manuale potrebbe essere un’opzione, ma non è nullo:

 queue.add(left as Node); 

Significato se lasciato è cambiato su un thread diverso, il programma si bloccherà.