Jak sprawdzić, czy zainicjowano zmienną „lateinit”?

428

Zastanawiam się, czy istnieje sposób sprawdzenia, czy lateinitzmienna została zainicjowana. Na przykład:

class Foo() {

    private lateinit var myFile: File

    fun bar(path: String?) {
        path?.let { myFile = File(it) }
    }

    fun bar2() {
        myFile.whateverMethod()
        // May crash since I don't know whether myFile has been initialized
    }
}
Mathew Hany
źródło
3
Może potrzebujesz, aby właściwość File?stała się pusta (zmień typ na ) i po prostu sprawdź, czy zamiast niej jest pusta?
Marcin Koziński,
1
Cóż, faktycznie próbowałem tego i to załatwi sprawę, jednak będę musiał edytować allSeriesvar seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), co nie jest zbyt „ładne”
Mathew Hany
1
Możesz zrobić zwykły stary test zerowy, a inteligentna obsada sprawi, że będzie ładniejszy. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński,
Proszę rozważyć przyjęcie bardziej aktualnej odpowiedzi
mizantrop

Odpowiedzi:

977

Jest lateinitpoprawa w Kotlin 1.2, która pozwala sprawdzić stan inicjalizacji lateinitzmiennej bezpośrednio:

lateinit var file: File    

if (this::file.isInitialized) { ... }

Zobacz ogłoszenie na blogu JetBrains lub propozycję KEEP .

AKTUALIZACJA: Kotlin 1.2 został wydany. lateinitUlepszenia można znaleźć tutaj:

xsveda
źródło
3
@ fer.marino: No cóż, Kotlin 1.2 pozwala na użycie lateinitrównież do zmiennych lokalnych, patrz kotlinlang.org/docs/reference/…
xsveda
9
this :: lateinitVar.isInitialized
vihkat
17
co to znaczy ::przedtem file?
Malwinder Singh
5
@MalwinderSingh tworzy odwołanie do członka lub odwołanie do klasy.
notGeek
5
Zakochany w kotlin teraz
Naveed Ahmad
46

Za pomocą .isInitializedwłaściwości można sprawdzić stan inicjalizacji zmiennej lateinit.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}
Nikhil Katekhaye
źródło
To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienia, zostaw komentarz pod postem. - Z recenzji
gforce301
2
@ gforce301 Zdecydowanie zostanie użyty do sprawdzenia.
Nikhil Katekhaye
39

Spróbuj go użyć, a otrzymasz, UninitializedPropertyAccessExceptionjeśli nie zostanie zainicjowany.

lateinitjest szczególnie przeznaczony do przypadków, w których pola są inicjowane po budowie, ale przed faktycznym użyciem (model używany przez większość platform wstrzykiwania). Jeśli tak nie jest, twój przypadek użycia lateinitmoże być niewłaściwy.

EDYCJA: Na podstawie tego, co chcesz zrobić, coś takiego działałoby lepiej:

val chosenFile = SimpleObjectProperty<File?>
val button: Button

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
Kiskae
źródło
Mam aplikację JavaFX i mam przycisk, który zawsze będzie wyłączany, chyba że zmienna (która jest lateinit) została zainicjowana. Innymi słowy: chcę, aby przycisk był wyłączony, dopóki zmienna nie zostanie zainicjowana. Czy jest na to dobry sposób?
Mathew Hany
@MathewHany Jak przebiegałoby to normalnie? Możesz spojrzeć na getter / setters właściwości i SimpleBooleanProperty, które możesz powiązać z wyłączoną właściwością przycisku
Kiskae
1
Mówiąc ściślej, mam prostą aplikację, która zawiera 4 przyciski, pierwszy przycisk otworzy okno dialogowe DirectoryChooser, a pozostałe 3 zostaną wyłączone, gdy użytkownik wybierze katalog, wówczas wszystkie pozostałe przyciski będą dostępne dla użytkownika.
Mathew Hany
@MathewHany możesz natywnie zaimplementować to za pomocą SimpleObjectProperty do przechowywania wybranego pliku, a następnie używając isNullpowiązania, aby wyłączyć inne przyciski.
Kiskae
1
kotlinlang.org/docs/reference/… xsveda odpowiedź jest bardziej aktualna
Serge
19

Możesz to łatwo zrobić:

::variableName.isInitialized

lub

this::variableName.isInitialized

Ale jeśli jesteś w słuchaczu lub klasie wewnętrznej, zrób to:

this@YourClassName::variableName.isInitialized

Uwaga: powyższe instrukcje działają poprawnie, jeśli zapisujesz je w tym samym pliku (tej samej klasie lub klasie wewnętrznej), w którym deklarowana jest zmienna, ale to nie zadziała, jeśli chcesz sprawdzić zmienną innej klasy (nie nadklasy lub zadeklarowanej w inny plik) , na przykład:

class Test {
    lateinit var str:String
}

I aby sprawdzić, czy str jest zainicjowany:

wprowadź opis zdjęcia tutaj

Co my tu robimy dostępu pola strw Testklasie w Test2klasie. I otrzymujemy błąd, że pole var nie jest w tym momencie dostępne. Sprawdź już zadane pytanie na ten temat.

Suraj Vaishnav
źródło
12

Zaakceptowana odpowiedź powoduje błąd kompilatora Kotlin 1.3+, musiałem wcześniej wyraźnie wspomnieć o tym thissłowie kluczowym ::. Poniżej znajduje się działający kod.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}
Sazzad Hissain Khan
źródło
Korzystam z lokalnej zmiennej init, gdy używam tego sprawdzania, które daje błąd podobny do nierozwiązanego odwołania
MarGin
3

Aby sprawdzić, czy lateinit varzostały zainicjowane, czy nie, użyj .isInitializedodwołania do tej właściwości:

if (foo::bar.isInitialized) {
    println(foo.bar)
}

To sprawdzenie jest dostępne tylko dla właściwości dostępnych leksykalnie, tj. Zadeklarowanych w tym samym typie lub w jednym z typów zewnętrznych lub na najwyższym poziomie w tym samym pliku.

Andy
źródło
1
co to znaczy ::przedtem bar?
Malwinder Singh
@Malwinder Singh „tworzy odwołanie do członka lub odwołanie do klasy” - Kotlin Doc
DMonkey
0
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Bytecode mówi ... bla bla ...

public final static synthetic access$getClientKeypair$p(Lcom/takharsh/ecdh/MainActivity;)Ljava/security/KeyPair;

`L0
LINENUMBER 11 L0
ALOAD 0
GETFIELD com/takharsh/ecdh/MainActivity.clientKeypair : Ljava/security/KeyPair;
DUP
IFNONNULL L1
LDC "clientKeypair"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwUninitializedPropertyAccessException (Ljava/lang/String;)V
    L1
ARETURN

L2 LOCALVARIABLE $ this Lcom / takharsh / ecdh / MainActivity; L0 L2 0 MAKSYMALNY = 2 MAKSYMALNE = 1

Kotlin tworzy dodatkową lokalną zmienną tej samej instancji i sprawdza, czy jest null, czy nie, jeśli null, wówczas „throwUninitializedPropertyAccessException” inaczej zwróci obiekt lokalny. Powyżej kodu bajtowego wyjaśnione tutaj rozwiązanie, ponieważ Kotlin 1.2 pozwala na sprawdzenie pogody lateinit var został zainicjowany lub nie stosując.isInitialized

takharsh
źródło