A początkujący Kotlin pyta: „dlaczego poniższy kod się nie skompiluje?”:
var left: Node? = null
fun show() {
if (left != null) {
queue.add(left) // ERROR HERE
}
}
Inteligentne rzutowanie na „Węzeł” jest niemożliwe, ponieważ „left” jest zmienną właściwością, którą do tego czasu można było zmienić
Rozumiem, że left
jest to zmienna zmienna, ale jawnie sprawdzam left != null
i left
jest typu, Node
więc dlaczego nie można go rzutować na ten typ?
Jak mogę to naprawić elegancko? :)
n.left?.let { queue.add(it) }
myślę?Odpowiedzi:
Między wykonaniem
left != null
aqueue.add(left)
innym wątkiem mogła zostać zmieniona wartośćleft
nanull
.Aby obejść ten problem, masz kilka opcji. Oto niektóre:
Użyj zmiennej lokalnej z inteligentnym rzutowaniem:
Użyj bezpiecznego połączenia, takiego jak jedno z poniższych:
Użyj operatora Elvis z,
return
aby wrócić wcześniej z funkcji zamykającej:Zauważ, że
break
icontinue
mogą być używane podobnie do kontroli w pętlach.źródło
Node
klasy zdefiniowanej w oryginalnej wersji pytania, która miała bardziej skomplikowany fragment kodun.left
zamiast po prostuleft
. Odpowiednio zaktualizowałem odpowiedź. Dzięki.val
dla każdegovar
, zagnieździć kilka?.let
instrukcji lub użyć kilku?: return
instrukcji w zależności od funkcji. npMyAsyncTask().execute(a1 ?: return, a2 ?: return, a3 ?: return)
. Możesz także wypróbować jedno z rozwiązań dla „wynajmu wielu zmiennych” .1) Możesz także użyć
lateinit
Jeśli na pewno wykonasz inicjalizację późniejonCreate()
lub w innym miejscu.Użyj tego
Zamiast tego
2) I istnieje inny sposób, w którym używasz
!!
końca zmiennej, gdy używasz go w ten sposóbźródło
Istnieje czwarta opcja oprócz tych w odpowiedzi mfulton26.
Za pomocą
?.
operatora można wywoływać metody oraz pola bez zajmowania sięlet
lub używania zmiennych lokalnych.Trochę kodu dla kontekstu:
Działa z metodami, polami i wszystkimi innymi rzeczami, które próbowałem uruchomić.
Aby więc rozwiązać problem, zamiast konieczności ręcznego rzutowania lub używania zmiennych lokalnych, możesz użyć
?.
metody wywoływania metod.Dla porównania przetestowano to w Kotlinie
1.1.4-3
, ale także w1.1.51
i1.1.60
. Nie ma gwarancji, że działa w innych wersjach, może to być nowa funkcja.W tym
?.
przypadku nie można użyć operatora, ponieważ jest to przekazywana zmienna, która jest problemem. Alternatywą może być operator Elvisa, który prawdopodobnie wymaga najmniejszej ilości kodu. Zamiast używaćcontinue
,return
można również użyć.Opcjonalne może być także użycie ręcznego rzutowania, ale nie jest to bezpieczne:
Oznacza to, że jeśli lewo zmieniło się w innym wątku, program się zawiesi.
źródło
left
i niequeue
. Trzeba to sprawdzić, edytuje odpowiedź za minutęPraktyczny powód, dla którego to nie działa, nie jest związany z wątkami. Chodzi o to, że
node.left
jest skutecznie przetłumaczone nanode.getLeft()
.Ten moduł pobierania właściwości można zdefiniować jako:
Dlatego dwa połączenia mogą nie zwracać tego samego wyniku.
źródło
Zmień
var left: Node? = null
nalateinit var left: Node
. Problem rozwiązany.źródło
Zrób to:
To wydaje się być pierwszą opcją podaną przez zaakceptowaną odpowiedź, ale właśnie tego szukasz.
źródło
Aby możliwe było inteligentne rzutowanie właściwości, typ danych właściwości musi być klasą zawierającą metodę lub zachowanie, do którego chcesz uzyskać dostęp, a NIE, że właściwość jest typu superklasy.
np. na Androida
Być:
Rozwiązanie:
Stosowanie:
GL
źródło
Najbardziej eleganckim rozwiązaniem musi być:
Wówczas nie musisz definiować nowej i niepotrzebnej zmiennej lokalnej i nie masz żadnych nowych asercji ani rzutowań (które nie są OSUSZANE). Inne funkcje zakresu również mogą działać, więc wybierz swój ulubiony.
źródło
Spróbuj użyć operatora asercji niepustej ...
źródło
Jak bym to napisał:
źródło