2016-08-04 67 views
19

W języku Kotlin domyślnie musimy zainicjować każdą zmienną po jej wprowadzeniu. Aby tego uniknąć, można użyć słowa kluczowego lateinit. Odwołanie się do zmiennej lateinit przed jej zainicjowaniem powoduje wyjątek środowiska wykonawczego.Dlaczego Kotlin nie pozwala używać lateinit z typami pierwotnymi?

lateinit nie można jednak używać z typami pierwotnymi. Dlaczego tak jest?

Odpowiedz

16

Dla typów obiektów, Kotlin używa wartości null aby zaznaczyć, że nieruchomość lateinit nie został zainicjowany i wrzucić odpowiedni wyjątek, gdy właściwość jest dostępna.

W przypadku typów pierwotnych nie ma takiej wartości, więc nie można oznaczyć właściwości jako niezainicjowanej i zapewnić diagnostykę, którą musi dostarczyć funkcja diagnostyczna. (Moglibyśmy spróbować użyć oddzielnego znacznika, ale ten znacznik nie byłby aktualizowany podczas inicjalizacji pola przez odbicie, co jest głównym przypadkiem użycia lateinit).

Dlatego lateinit jest obsługiwany tylko dla właściwości typów obiektów.

+31

Czy mógłbyś wyjaśnić w odpowiedzi, dlaczego 'lateinit Int' nie może być reprezentowany przez typ" Integer "w środowisku wykonawczym, który jest w stanie utrzymać wartość' null', podczas gdy nie została zainicjowana? – Ilya

+0

@Ilya, ponieważ 'Integer' nie jest' int'. Jest to typ pudełkowy i ma znaczenie przy ustawianiu rzeczy natywnie lub poprzez odbicie. –

+2

Myślę więc, że Kotlin zawija typy pierwotne do obiektu (na przykład int do Int). Dlaczego jednak funkcja Int nie może mieć wartości null, ponieważ jest to obiekt? Dlaczego nie możemy zadeklarować parametru jako zerowalnego i opóźnić go? (var x: Int?) – Yao

1

Krótka odpowiedź jest taka, że ​​w przypadku prymitywów zawsze można użyć domyślnie 0, a domyślnie dopuszcza się typy zerowane null. Jedynie nie-nullowalne, nieprymitywne typy mogą wymagać, aby pracować wokół systemu bezpieczeństwa typu.

Faktycznie, nie ma potrzeby inicjowania zmiennej w Kotlin tak długo, jak to ma wartość przed pierwszy dostęp i może być statycznie udowodnione. Co oznacza, że ​​kod ten jest całkowicie ważny:

fun main(args: Array<String>) { 
    var x: Int 
    val y: Double 

    x = 0 
    y = x + 0.1 

    println("$x, $y") 
} 

Istnieją jednak (rzadkie) przypadki, w których inicjalizacja nie może zostać udowodniona statycznie. Najczęstszym przypadkiem jest polem klasy, który wykorzystuje każdą formę zastrzyku Zależność:

class Window { 
    @Inject lateinit parent: Parent 
} 
Powiązane problemy