จะตรวจสอบได้อย่างไรว่าตัวแปร“ Lateinit” ได้รับการเริ่มต้นแล้ว?


428

ฉันสงสัยว่ามีวิธีการตรวจสอบว่าlateinitตัวแปรได้รับการเริ่มต้น ตัวอย่างเช่น:

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
บางทีสิ่งที่คุณต้องการคือการทำให้คุณสมบัติFile?เป็นโมฆะ(เปลี่ยนประเภทเป็น) และเพียงตรวจสอบว่ามันเป็นโมฆะแทน?
Marcin Koziński

1
จริง ๆ แล้วฉันพยายามทำเช่นนั้นและจะทำกลอุบาย แต่ฉันจะต้องแก้ไขallSeriesvar ไปseriesDir?.listFiles()?.map { it.name }?.toTypedArray()ซึ่งไม่ใช่ "สวย" มาก
Mathew Hany

1
คุณสามารถทำการตรวจสอบโมฆะเก่า ๆ แบบธรรมดาได้และสมาร์ทแคสต์จะทำให้มันสวยขึ้น if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński

โปรดพิจารณาการยอมรับมากขึ้นถึงวันที่คำตอบ
เกลียด

คำตอบ:


977

มีการlateinitปรับปรุงใน Kotlin 1.2 ที่อนุญาตให้ตรวจสอบสถานะการเริ่มต้นของlateinitตัวแปรได้โดยตรง:

lateinit var file: File    

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

ดูประกาศในJetBrains บล็อกหรือข้อเสนอ KEEP

อัปเดต: Kotlin 1.2 เปิดตัวแล้ว คุณสามารถค้นหาlateinitการปรับปรุงที่นี่:


3
@ fer.marino: จริง ๆ แล้ว Kotlin 1.2 ช่วยให้คุณสามารถใช้lateinitกับตัวแปรท้องถิ่นได้ด้วยดูที่kotlinlang.org/docs/reference/…
xsveda

9
this :: lateinitVar.isInitialized
vihkat

17
ความหมายของอะไร::ก่อนหน้านี้file?
Malwinder Singh

5
@MalwinderSingh มันสร้างการอ้างอิงสมาชิกหรือการอ้างอิงระดับ
notGeek

5
ในความรักกับ Kotlin ตอนนี้
Naveed Ahmad

46

การใช้.isInitializedคุณสมบัติหนึ่งสามารถตรวจสอบสถานะการเริ่มต้นของตัวแปรล่าช้าได้

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

สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม หากต้องการวิจารณ์หรือขอคำชี้แจงจากผู้แต่งโปรดแสดงความคิดเห็นใต้โพสต์ของพวกเขา - จากการรีวิว
gforce301

2
@ gforce301 มันจะใช้สำหรับการตรวจสอบอย่างแน่นอน
Nikhil Katekhaye

39

ลองใช้มันและคุณจะได้รับUninitializedPropertyAccessExceptionถ้ามันไม่ได้เริ่มต้น

lateinitใช้สำหรับกรณีที่มีการเริ่มต้นฟิลด์หลังจากการก่อสร้าง แต่ก่อนการใช้งานจริง (โมเดลที่เฟรมเวิร์กการฉีดส่วนใหญ่ใช้) หากนี่ไม่ใช่กรณีการใช้งานของคุณlateinitอาจไม่ใช่ตัวเลือกที่ถูกต้อง

แก้ไข: ขึ้นอยู่กับสิ่งที่คุณต้องการทำอะไรเช่นนี้จะทำงานได้ดีขึ้น:

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

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

ฉันมีแอปพลิเคชัน JavaFX และฉันมีปุ่มที่จะปิดการใช้งานเสมอยกเว้นตัวแปร (ซึ่งคือlateinit) ได้รับการเริ่มต้น กล่าวอีกนัยหนึ่ง: ฉันต้องการให้ปุ่มถูกปิดใช้งานตราบใดที่ตัวแปรไม่ได้ถูกกำหนดค่าเริ่มต้น มีวิธีที่ดีในการทำเช่นนั้น?
Mathew Hany

@MathewHany วิธีการเริ่มต้นปกติได้อย่างไร คุณอาจต้องการดูคุณสมบัติ getter / setters และ SimpleBooleanProperty ซึ่งคุณสามารถผูกกับคุณสมบัติของปุ่มที่ถูกปิดใช้งานได้
Kiskae

1
เฉพาะเจาะจงมากขึ้นฉันมีแอพง่าย ๆ ที่มี 4 ปุ่มปุ่มแรกจะเปิดไดอะล็อก DirectoryChooser และอีก 3 รายการจะถูกปิดใช้งานเมื่อผู้ใช้เลือกไดเรกทอรีจากนั้นปุ่มอื่น ๆ ทั้งหมดจะพร้อมใช้งานสำหรับผู้ใช้
Mathew Hany

@MathewHany คุณสามารถนำไปปฏิบัติได้โดยใช้ SimpleObjectProperty เพื่อเก็บไฟล์ที่เลือกจากนั้นใช้การisNullเชื่อมเพื่อปิดใช้งานปุ่มอื่น
Kiskae

1
kotlinlang.org/docs/reference/…คำตอบ xsveda เป็นข้อมูลที่ทันสมัยมากขึ้น
Serge

19

คุณสามารถทำได้โดย:

::variableName.isInitialized

หรือ

this::variableName.isInitialized

แต่ถ้าคุณอยู่ในกลุ่มผู้ฟังหรือคนชั้นในให้ทำดังนี้

this@YourClassName::variableName.isInitialized

หมายเหตุ: ข้อความข้างต้นใช้งานได้ดีหากคุณกำลังเขียนในไฟล์เดียวกัน (คลาสเดียวกันหรือคลาสภายใน) ที่มีการประกาศตัวแปร แต่จะไม่ทำงานหากคุณต้องการตรวจสอบตัวแปรของคลาสอื่น (ไม่ใช่ซูเปอร์คลาสหรือประกาศใน ไฟล์อื่น)เช่น:

class Test {
    lateinit var str:String
}

และเพื่อตรวจสอบว่ามีการเริ่มต้น str:

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งที่เรากำลังทำอะไรที่นี่ในการเข้าถึงข้อมูลstrของTestการเรียนในTest2ชั้นเรียน และเราได้รับข้อมูลสำรองข้อผิดพลาดของ var ไม่สามารถเข้าถึงได้ ณ จุดนี้ ตรวจสอบคำถามที่ตั้งขึ้นเกี่ยวกับเรื่องนี้


12

คำตอบที่ได้รับการยอมรับให้ฉันรวบรวมข้อผิดพลาดในKotlin 1.3+ผมต้องชัดเจนพูดถึงคำหลักก่อนthis ::ด้านล่างเป็นรหัสที่ใช้งานได้

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}

ฉันใช้ตัวแปร init แบบโลคัลเมื่อฉันใช้การตรวจสอบนี้ซึ่งให้ข้อผิดพลาดเช่นการอ้างอิงที่ไม่ได้รับการแก้ไข
MarGin

3

ในการตรวจสอบว่ามีการlateinit varเตรียมใช้งานหรือไม่ใช้ a .isInitializedในการอ้างอิงถึงคุณสมบัตินั้น:

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

การตรวจสอบนี้จะใช้ได้เฉพาะกับคุณสมบัติที่เข้าถึงได้โดยทั่วไปเช่นประกาศในประเภทเดียวกันหรือในประเภทด้านนอกประเภทใดประเภทหนึ่งหรือที่ระดับบนสุดในไฟล์เดียวกัน


1
ความหมายของอะไร::ก่อนหน้านี้bar?
Malwinder Singh

@Malwinder Singh "สร้างการอ้างอิงสมาชิกหรือการอ้างอิงระดับ" - Kotlin Doc
DMonkey

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

Bytecode พูดว่า ... 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 ท้องถิ่น $ Lcom นี้ / takharsh / ecdh / MainActivity; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1

Kotlin สร้างตัวแปรท้องถิ่นพิเศษของอินสแตนซ์เดียวกันและตรวจสอบว่าเป็นโมฆะหรือไม่ถ้าเป็นโมฆะแล้วโยน 'throwUninitializedPropertyAccessException' อื่นกลับวัตถุท้องถิ่น bytecode ด้านบนอธิบายไว้ที่นี่ วิธีแก้ปัญหาตั้งแต่ kotlin 1.2 จะช่วยให้สามารถตรวจสอบสภาพอากาศช่วงเวลาที่เริ่มต้นหรือไม่ได้ใช้งาน.isInitialized

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.