מחלקות נתונים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Kotlin של Coddy. שיעור 32 מתוך 57.
מחלקת נתונים היא מחלקה שתפקידה העיקרי הוא להחזיק נתונים. משנה הגישה data גורם למהדר ליצור את toString(), equals(), hashCode(), copy() ואת componentN() מתוך המאפיינים של הבנאי הראשי:
data class Point(val x: Int, val y: Int)בתוך main:
val a = Point(1, 2)
val b = Point(1, 2)
println(a)
println(a == b)
println(setOf(a, b).size)פלט:
Point(x=1, y=2)
true
1ללא data, println מציגה את שם המחלקה וקוד גיבוב כגון Point@1b6d3586, ושני אובייקטים עם אותם ערכים אינם שווים. copy() יוצרת אובייקט חדש עם כמה מאפיינים ששונו ומשאירה את המקורי כפי שהוא, כך שמחלקת נתונים עם מאפייני val משמשת כערך בלתי ניתן לשינוי:
data class User(val name: String, val email: String, val admin: Boolean = false)בתוך main:
val ada = User("Ada", "ada@example.com")
val boss = ada.copy(admin = true)
println(ada)
println(boss)
println(ada == boss)פלט:
User(name=Ada, email=ada@example.com, admin=false)
User(name=Ada, email=ada@example.com, admin=true)
falseהצהרות פירוק מפרקות אובייקט למשתנים: val (x, y) = point קוראת ל־component1() ול־component2() שנוצרות אוטומטית, לפי סדר הבנאי. הדבר עובד גם בלולאות for ובפרמטרים של למבדה, ו־_ מדלג על מאפיין:
data class Score(val player: String, val points: Int, val level: Int)בתוך main:
val scores = listOf(Score("ada", 120, 3), Score("bo", 95, 2))
for ((player, points) in scores) println("$player: $points")
val (_, bestPoints, bestLevel) = scores.maxBy { it.points }
println("best: $bestPoints at level $bestLevel")פלט:
ada: 120
bo: 95
best: 120 at level 3רק מאפייני הבנאי הראשי משתתפים: מאפיין שמוצהר בגוף המחלקה אינו נכלל ב-toString, ב-equals, ב-hashCode וב-copy. למחלקת נתונים חייב להיות לפחות פרמטר אחד בבנאי, וכל פרמטר חייב להיות val או var:
data class Reading(val sensor: String, val value: Int) {
var note = ""
}בתוך main:
val r1 = Reading("t1", 20)
val r2 = Reading("t1", 20)
r1.note = "checked"
println(r1)
println(r1 == r2)פלט:
Reading(sensor=t1, value=20)
trueאתגר
קלהפוך את Book למחלקת נתונים כדי שהיא תודפס ותושווה לפי ערך. לאחר מכן השלם שלוש פונקציות: parse(line) ממירה את Dune;Herbert;1965 ל-Book, newEdition(book, year) מחזירה עותק עם השנה החדשה ועם (new edition) שנוסף לכותרת, ו-describe(book) מחזירה את Dune by Herbert, 1965 באמצעות הצהרת פירוק.
הקוד שסופק מנתח כל שורת קלט, מדפיס כל ספר, את מספר הכפילויות, את המהדורה החדשה של הספר הראשון (שנה 2024) ותיאור של כל ספר ייחודי.
הקוד שלך צריך להיות בקבצים Book.kt ו-BookTools.kt. הקובץ Main.kt מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
fun main() {
// קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
val input = generateSequence(::readLine).toList()
val books = input.map { parse(it) }
for (b in books) println(b)
println("duplicates: ${books.size - books.distinct().size}")
println(newEdition(books[0], 2024))
for (b in books.distinct()) println(describe(b))
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1מחלקות ואובייקטים
עבודה עם קבציםהגדרת מחלקותבנאים ראשייםבלוקי init ואימות נתוניםבנאים משנייםסיכום – כרטיס ספרייה7מחלקות מיוחדות
מחלקות נתוניםמחלקות Enumהיררכיות אטומותequals, hashCode, toStringחזרה – מעקב אחר הזמנותתרגלו בעצמכם: Kotlin אונליין