Làm thế nào để kiểm tra xem một biến muộn muộn đã được khởi tạo?


428

Tôi tự hỏi nếu có một cách để kiểm tra nếu một lateinitbiến đã được khởi tạo. Ví dụ:

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
    }
}

3
Có lẽ những gì bạn cần là làm cho thuộc tính nullable (thay đổi loại thành File?) và chỉ kiểm tra xem nó có null không?
Marcin Koziński

1
Chà, tôi thực sự đã thử nó và nó sẽ thực hiện được mẹo, tuy nhiên tôi sẽ phải chỉnh sửa allSeriesvar thành seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), nó không "đẹp" lắm
Mathew Hany

1
Bạn có thể làm một kiểm tra null cũ đơn giản và diễn viên thông minh sẽ làm cho nó đẹp hơn. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński

Vui lòng xem xét chấp nhận câu trả lời
misanthrope

Câu trả lời:


977

Có một lateinitcải tiến trong Kotlin 1.2 cho phép kiểm tra lateinittrực tiếp trạng thái khởi tạo của biến:

lateinit var file: File    

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

Xem thông báo trên blog JetBrains hoặc đề xuất KEEP .

CẬP NHẬT: Kotlin 1.2 đã được phát hành. Bạn có thể tìm thấy các lateinitcải tiến ở đây:


3
@ fer.marino: Vâng, Kotlin 1.2 thực sự cho phép bạn sử dụng lateinitcũng cho các biến địa phương, xem kotlinlang.org/docs/reference/...
xsveda

9
this :: lateinitVar.isInitialized
vihkat

17
ý nghĩa của ::trước đây là filegì?
Malwinder Singh

5
@MalwinderSingh nó tạo ra một tham chiếu thành viên hoặc một tham chiếu lớp.
phải

5
Đang yêu kotlin bây giờ
Naveed Ahmad

46

Sử dụng thuộc .isInitializedtính người ta có thể kiểm tra trạng thái khởi tạo của một biến lateinit.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}

Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ. - Từ đánh giá
gforce301

2
@ gforce301 Nó chắc chắn sẽ được sử dụng để kiểm tra.
Nikhil Katekhaye

39

Hãy thử sử dụng nó và bạn sẽ nhận được UninitializedPropertyAccessExceptionnếu nó không được khởi tạo.

lateinitđặc biệt cho các trường hợp các trường được khởi tạo sau khi xây dựng, nhưng trước khi sử dụng thực tế (một mô hình mà hầu hết các khung tiêm sử dụng). Nếu đây không phải là trường hợp sử dụng của bạnlateinit có thể không phải là lựa chọn đúng đắn.

EDIT: Dựa trên những gì bạn muốn làm một cái gì đó như thế này sẽ hoạt động tốt hơn:

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

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())

Tôi có một ứng dụng JavaFX và tôi có một nút sẽ luôn vô hiệu hóa trừ khi một biến (đó là lateinit) đã được khởi tạo. Nói cách khác: Tôi muốn nút này bị vô hiệu hóa miễn là biến chưa được khởi tạo. Có một cách tốt để làm điều đó?
Mathew Hany

@MathewHany Làm thế nào để nó được khởi tạo bình thường? Bạn có thể muốn xem getter / setters thuộc tính và SimpleBooleanProperty mà bạn có thể liên kết với thuộc tính bị vô hiệu hóa của nút
Kiskae

1
Để cụ thể hơn, tôi có một ứng dụng đơn giản chứa 4 nút, nút đầu tiên sẽ mở hộp thoại DirectoryChooser và 3 nút còn lại sẽ bị vô hiệu hóa, khi người dùng chọn một thư mục thì tất cả các nút khác sẽ có sẵn cho người dùng.
Mathew Hany

@MathewHany bạn có thể thực hiện điều đó bằng cách sử dụng SimpleObjectProperty để giữ tệp đã chọn, sau đó sử dụng isNullliên kết để vô hiệu hóa các nút khác.
Kiskae

1
kotlinlang.org/docs/reference/ Câu trả lời xsveda cập nhật hơn
Serge

19

Bạn có thể dễ dàng làm điều này bằng cách:

::variableName.isInitialized

hoặc là

this::variableName.isInitialized

Nhưng nếu bạn ở trong một người nghe hoặc lớp bên trong, hãy làm điều này:

this@YourClassName::variableName.isInitialized

Lưu ý: Các câu lệnh trên hoạt động tốt nếu bạn viết chúng trong cùng một tệp (cùng lớp hoặc lớp bên trong) trong đó biến được khai báo nhưng điều này sẽ không hoạt động nếu bạn muốn kiểm tra biến của lớp khác (không phải siêu lớp hoặc khai báo trong một tệp khác) , ví dụ:

class Test {
    lateinit var str:String
}

Và để kiểm tra xem str có được khởi tạo không:

nhập mô tả hình ảnh ở đây

Những gì chúng ta đang làm ở đây truy cập vào lĩnh vực strcủa Testlớp trong Test2lớp. Và chúng tôi nhận được một trường sao lưu lỗi của var không thể truy cập tại thời điểm này. Kiểm tra một câu hỏi đã được nêu ra về điều này.


12

Câu trả lời được chấp nhận cho tôi một lỗi trình biên dịch Kotlin 1.3+, tôi đã phải đề cập rõ ràng thistừ khóa trước đó ::. Dưới đây là mã làm việc.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}

Tôi đang sử dụng biến init cục bộ khi tôi sử dụng kiểm tra này gây ra lỗi như tham chiếu chưa được giải quyết
MarGin

3

Để kiểm tra xem a lateinit varđã được khởi tạo hay chưa sử dụng a .isInitializedtrên tham chiếu đến thuộc tính đó:

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

Việc kiểm tra này chỉ khả dụng đối với các thuộc tính có thể truy cập theo từ vựng, nghĩa là được khai báo cùng loại hoặc ở một trong các loại bên ngoài hoặc ở cấp cao nhất trong cùng một tệp.


1
ý nghĩa của ::trước đây là bargì?
Malwinder Singh

@Malwinder Singh "tạo tham chiếu thành viên hoặc tham chiếu lớp" - Kotlin Doc
DMonkey

0
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Bytecode nói ... blah blah ..

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 ĐỊA PHƯƠNG $ Lcom / takharsh / ecdh / MainActivity; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1

Kotlin tạo ra một biến cục bộ bổ sung của cùng một thể hiện và kiểm tra xem nó có null hay không, nếu null thì ném 'throwUninitializedPropertyAccessException' khác trả về đối tượng cục bộ. Mã byte trên đã giải thích ở đây Giải pháp Vì kotlin 1.2, nó cho phép kiểm tra thời tiết trễ varinit đã được khởi tạo hay không sử dụng.isInitialized

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.