2017-06-16 18 views
42

Nowicjusz Kotlin pyta: "dlaczego poniższy kod nie zostanie skompilowany?":Inteligentne rzucanie do "Typu" jest niemożliwe, ponieważ "zmienna" jest zmienną właściwością, która mogła zostać zmieniona do tego czasu.

var left: Node? = null 

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

Inteligentne oddanych do „Węzła” jest niemożliwe, ponieważ „w lewo” jest zmienny właściwość, która mogła zostać zmieniona przez ten czas

otrzymuję że left jest zmienny zmienny , ale wyraźnie sprawdzam, czy left != null i left jest typu Node, więc dlaczego nie można go inteligentnie rzutować na ten typ?

Jak mogę to naprawić elegancko? :)

+2

Gdzieś pomiędzy różnymi wątkami można było ponownie zmienić wartość na zero. Jestem prawie pewien, że odpowiedzi na inne pytania również to wspominają. – nhaarman

+1

Możesz użyć [bezpiecznego połączenia] (https://kotlinlang.org/docs/reference/null-safety.html#safe-calls), aby dodać – Whymarrh

+0

dzięki @nhaarman, co ma sens, Whymarrh, jak to zrobić? Sądziłem, że bezpieczne połączenia dotyczą tylko obiektów, a nie metod. – feresr

Odpowiedz

60

Pomiędzy wykonaniem n.left != null i queue.add(n.left) inny wątek mógł zmienić wartość n.left na null.

Aby temu zaradzić, masz kilka opcji. Oto niektóre:

  1. użyć zmiennej lokalnej z inteligentnego Obsada:

    val left = n.left 
    if (left != null) { 
        queue.add(left) 
    } 
    
  2. Skorzystaj z safe call takie jak jedną z następujących czynności:

    n.left?.let { left -> queue.add(left) } 
    n.left?.let { queue.add(it) } 
    n.left?.let(queue::add) 
    
  3. Użyj Elvis operator z jump do następnego kroku otaczającej pętli while:

    queue.add(n.left ?: continue) 
    
+0

4. Pomyśl o bardziej funkcjonalnym rozwiązaniu problemu, który nie wymaga zmiennych zmiennych. –

1

Jest czwarta opcja oprócz tych w odpowiedzi mfulton26 użytkownika.

Korzystając z operatora ?. można wywoływać metody, jak również pola bez obsługi let lub przy użyciu zmiennych lokalnych.

Niektóre kodu dla kontekstu:

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

Współpracuje z metod, pól i wszystkich innych rzeczy, które starały się zmusić go do pracy.

Aby rozwiązać problem, zamiast używać ręcznych rzutów lub zmiennych lokalnych, można użyć metody ?..

Dla odniesienia, zostało to przetestowane w Kotlin 1.1.4-3, ale również przetestowane w 1.1.51 i 1.1.60. Nie ma gwarancji, że działa w innych wersjach, może to być nowa funkcja.

Używanie operatora ?. nie może być używane w twoim przypadku, ponieważ to jest przekazywana zmienna, która jest problemem. Operator Elvisa może być używany jako alternatywa i prawdopodobnie wymaga najmniejszej ilości kodu. Zamiast tego można użyć continue, return.

Korzystanie ręcznego odlewania może być również opcja, ale to nie jest null bezpieczne:

queue.add(left as Node); 

Znaczenie pozostawione zmieniła w innym wątku, program będzie awarię.

+0

O ile rozumiem, "?." operator sprawdza, czy zmienna po lewej stronie ma wartość null. W powyższym przykładzie będzie to "kolejka". Błąd "smart cast impossible" odnosi się do parametru "left" przekazanego do metody "add" ... Nadal dostaję błąd, jeśli używam tego podejścia – feresr

+0

W porządku, błąd dotyczy 'left', a nie' queue '. Musisz to sprawdzić, zredaguję odpowiedź za minutę – Zoe