lazy ו־lateinit
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Kotlin של Coddy. שיעור 10 מתוך 57.
by lazy { ... } דוחה את חישוב ה־val עד לקריאה הראשונה שלו, ואז שומרת את התוצאה. היא מתאימה לערכים שהחישוב שלהם יקר או שלא תמיד נחוצים:
class Report(val rows: List<Int>) {
val summary: String by lazy {
println("computing summary")
"total ${rows.sum()}"
}
}בתוך main:
val r = Report(listOf(3, 4))
println("created")
println(r.summary)
println(r.summary)פלט:
created
computing summary
total 7
total 7הבלוק רץ פעם אחת: הקריאה השנייה למעלה השתמשה בתוצאה השמורה. בניגוד ל-getter מותאם אישית, שרץ בכל קריאה, lazy מחשב פעם אחת ושומר את התוצאה במטמון:
class Demo {
var reads = 0
val viaGetter: Int
get() { reads++; return 42 }
val viaLazy: Int by lazy { reads++; 42 }
}בתוך main:
val d = Demo()
repeat(3) { d.viaGetter; d.viaLazy }
println(d.reads)פלט:
4lateinit var מצהיר על מאפיין שאינו יכול להיות null, ושמקבל ערך מאוחר יותר, לאחר יצירת האובייקט, למשל באמצעות מתודת הגדרה. קריאה שלו לפני שהוקצה לו ערך תגרום לחריגה, ואילו ::name.isInitialized בודק אם הוקצה לו ערך:
class Screen {
lateinit var title: String
fun load(t: String) { title = t }
fun ready() = ::title.isInitialized
}בתוך main:
val s = Screen()
println(s.ready())
s.load("Home")
println(s.ready())
println(s.title)פלט:
false
true
Homeהעדף אתחול רגיל כשהערך ידוע בעת הבנייה. השתמש ב-lazy עבור val יקר לחישוב שייתכן שלא יהיה בו צורך, וב-lateinit רק עבור var שהערך שלו אכן מתקבל מאוחר יותר; lateinit לא עובד עם Int, Boolean או טיפוסים פרימיטיביים אחרים.
val config by lazy { loadConfig() } // מחושב פעם אחת, בשימוש הראשון
lateinit var user: User // מקבל ערך לאחר היצירה
// lateinit var count: Int // שגיאה: לא מותר עבור טיפוסים פרימיטיבייםאתגר
קלהשלימו את המחלקה Document(val text: String). הוסיפו את wordCount כמאפיין lazy שסופר את המילים (המופרדות ברווחים בודדים) ומתעד כל חישוב על ידי הוספת 1 ל-computations, וכן lateinit var author: String עם שיטה credit() שמחזירה by Ada או by unknown כאשר המחבר עדיין לא הוגדר.
הקוד שסופק קורא את הטקסט, קורא את wordCount שלוש פעמים, מגדיר את המחבר כשיש שורה שנייה, ומדפיס את words 5, computed 1, by Ada.
הקוד שלכם יופיע ב-Document.kt. הקובץ Main.kt מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
fun main() {
// קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
val input = generateSequence(::readLine).toList()
val doc = Document(input[0])
val reads = List(3) { doc.wordCount }
val words = reads.first()
if (input.size > 1) doc.author = input[1]
println("words $words, computed ${doc.computations}, ${doc.credit()}")
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1מחלקות ואובייקטים
עבודה עם קבציםהגדרת מחלקותבנאים ראשייםבלוקי init ואימות נתוניםבנאים משנייםסיכום – כרטיס ספרייהתרגלו בעצמכם: Kotlin אונליין