מעבדת קוד זו היא חלק מקורס האתחול של מתכנתים בקוטלין. כדי להפיק את המקסימום מהקורס הזה, יש לפעול ברצף לפי קודי שיעור ה-Lab. בהתאם לידע שלכם, ייתכן שתוכלו לדלג על קטעים מסוימים. הקורס הזה מיועד למתכנתים בעלי שפה ממוקדת אובייקטים שרוצים ללמוד Kotlin.
מבוא
בשיעור Lab זה תקבלו קורסים, פונקציות ושיטות גנריות, וכן על האופן שבו הם עובדים ב-Kotlin.
במקום לפתח אפליקציה לדוגמה אחת, השיעורים בקורס הזה נועדו לפתח את הידע שלכם, אך אינם תלויים זה בזה כדי שתוכלו לעיין בסעיפים שאתם מכירים. כדי לקשר ביניהם, רבות מהדוגמאות משתמשות בעיצוב של אקווריום. אם אתם רוצים לראות את הסיפור המלא באקווריום, כדאי לנסות את הקורס של מתכנתים בקוטג'ין באוניברסיטה.
דברים שחשוב לדעת
- התחביר, הפונקציות והשיטות של Kotlin
- איך יוצרים כיתה חדשה ב- IntelliJ IDEA ומפעילים תוכנית?
מה תלמדו
- איך לעבוד עם כיתות, שיטות ופונקציות גנריות
הפעולות שתבצעו:
- יצירת מחלקה כללית והוספת אילוצים
- יצירת
in
ו-out
סוגים - יצירת פונקציות, שיטות ופונקציות כלליות
מבוא לגנריות
לקוטלין, כמו בשפות תכנות רבות, יש סוגים כלליים. סוג גנרי מאפשר להפוך את הכיתה לגנרית, וכך להפוך את הכיתה לגמישה יותר.
נניח שהטמעת שיעור אחד (MyList
) שמכיל רשימת פריטים. ללא נתונים כלליים, עליך ליישם גרסה חדשה של MyList
עבור כל סוג: אחת עבור Double
, אחת עבור String
, אחת עבור Fish
. באופן כללי, אפשר ליצור רשימה גנרית, כך שהיא תוכל להכיל כל סוג של אובייקט. זה דומה ליצירת תו כללי לחיפוש שיתאים לסוגים רבים.
כדי להגדיר סוג גנרי, מוסיפים T בסוגריים מרובעים <T>
אחרי שם הכיתה. (ניתן להשתמש באות אחרת או בשם ארוך יותר, אך הנוהג של סוג גנרי הוא T).
class MyList<T> {
fun get(pos: Int): T {
TODO("implement")
}
fun addItem(item: T) {}
}
אפשר להפנות את T
כאילו הוא סוג רגיל. סוג ההחזרה של get()
הוא T
, והפרמטר אל addItem()
הוא מסוג T
. כמובן שרשימות גנריות שימושיות מאוד, ולכן הסיווג של List
מובנה ב-Kotlin.
שלב 1: יצירת היררכיית סוג
בשלב זה תיצרו כיתות נוספות בשלב הבא. סיווג המשנה נכלל בשיעור קוד קודם, אבל לפניכם בדיקה קצרה.
- כדי שדוגמה לא תהיה עמוסה יותר, אפשר ליצור חבילה חדשה בקטע src ולקרוא לה
generics
. - בחבילה הגנרית, יוצרים קובץ
Aquarium.kt
חדש. כך תוכל להגדיר מחדש פריטים באמצעות אותם שמות ללא התנגשויות, כך ששאר קוד הקוד עבור מעבד קוד זה יעבור לקובץ זה. - יצירת היררכיה של סוגים של ספקי מים. תחילה עליך ליצור כיתה אחת (
WaterSupply
) כדי להעביר אותה למחלקהopen
. - יש להוסיף פרמטר בוליאני
var
,needsProcessing
. כך נוצר באופן אוטומטי נכס משתנה, יחד עם getter ו-Setter. - יש ליצור מחלקת משנה
TapWater
שחורגת מ-WaterSupply
ועוברת אתtrue
בשבילneedsProcessing
, כי מי ההקשה מכילים תוספים שלא מתאימים לדגים. - במדיניות
TapWater
, מגדירים פונקציה בשםaddChemicalCleaners()
שמגדירה את הערךneedsProcessing
כ-false
לאחר ניקוי המים. אפשר להגדיר את הנכסneedsProcessing
מ-TapWater
כי הואpublic
כברירת מחדל ונגיש לכיתות משנה. הנה הקוד המלא.
package generics
open class WaterSupply(var needsProcessing: Boolean)
class TapWater : WaterSupply(true) {
fun addChemicalCleaners() {
needsProcessing = false
}
}
- יצירת שתי קטגוריות משנה נוספות של
WaterSupply
, שנקראתFishStoreWater
ו-LakeWater
. אין צורך לעבד אתFishStoreWater
. עם זאת, צריך לסנן אתLakeWater
באמצעות השיטהfilter()
. לאחר הסינון, אין צורך לעבד אותו שוב, כך שב-filter()
יש להגדיר אתneedsProcessing = false
.
class FishStoreWater : WaterSupply(false)
class LakeWater : WaterSupply(true) {
fun filter() {
needsProcessing = false
}
}
אם יש לך צורך במידע נוסף, כדאי לעיין בשיעור הקודם בנושא ירושה בקוטלין.
שלב 2: יצירת כיתה גנרית
בשלב זה, אתם משנים את המחלקה Aquarium
כדי לתמוך בסוגים שונים של ציוד מים.
- ב-Aquaium.kt, מגדירים כיתה
Aquarium
, כאשר<T>
מוסיפים סוגריים אחרי שם הכיתה. - צריך להוסיף נכס קבוע מסוג
waterSupply
מסוגT
ל-Aquarium
.
class Aquarium<T>(val waterSupply: T)
- צריך לכתוב פונקציה בשם
genericsExample()
. החלק הזה לא שייך לכיתה, ולכן הוא יכול להיות ברמה העליונה של הקובץ, כמו הפונקציהmain()
או הגדרות הכיתה. בפונקציה, מבצעיםAquarium
ומעבירים אותו ל-WaterSupply
. מכיוון שהפרמטרwaterSupply
הוא כללי, צריך לציין את הסוג בסוגריים מרובעים<>
.
fun genericsExample() {
val aquarium = Aquarium<TapWater>(TapWater())
}
- ב-
genericsExample()
הקוד שלך יכול לגשת אל האקווריוםwaterSupply
. מאחר שהוא מסוגTapWater
, אפשר להתקשר ל-addChemicalCleaners()
בלי להעביר מכל סוג שהוא.
fun genericsExample() {
val aquarium = Aquarium<TapWater>(TapWater())
aquarium.waterSupply.addChemicalCleaners()
}
- כשיוצרים את האובייקט
Aquarium
, אפשר להסיר את סוגריים הזווית ואת מה שביניהם כי ל-Kotlin יש הסקת סוג. לכן אין סיבה לומרTapWater
פעמיים כשיוצרים את המכונה. ניתן להסיק את הסוג הזה על-ידי הארגומנטAquarium
. הוא עדיין ייצורAquarium
מסוגTapWater
.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
aquarium.waterSupply.addChemicalCleaners()
}
- כדי לראות מה קורה, מדפיסים את
needsProcessing
לפני ואחרי השיחה ל-addChemicalCleaners()
. לפניכם הפונקציה שהושלמה.
fun genericsExample() {
val aquarium = Aquarium<TapWater>(TapWater())
println("water needs processing: ${aquarium.waterSupply.needsProcessing}")
aquarium.waterSupply.addChemicalCleaners()
println("water needs processing: ${aquarium.waterSupply.needsProcessing}")
}
- צריך להוסיף פונקציה
main()
כדי להתקשר אלgenericsExample()
, להפעיל את התוכנית ולצפות בתוצאה.
fun main() {
genericsExample()
}
⇒ water needs processing: true water needs processing: false
שלב 3: הגדרה ספציפית יותר
המונח 'כללי' פירושו שניתן להעביר כמעט כל דבר, ולפעמים זו בעיה. בשלב זה, הופכים את הכיתה ל-Aquarium
ספציפית יותר במה שאפשר לכלול בה.
- באפליקציה
genericsExample()
, יש ליצורAquarium
, להעביר מחרוזת עבורwaterSupply
ולהדפיס את נכס האקווריוםwaterSupply
.
fun genericsExample() {
val aquarium2 = Aquarium("string")
println(aquarium2.waterSupply)
}
- מפעילים את התוכנית וצופים בתוצאה.
⇒ string
התוצאה היא המחרוזת שהעברת, כי Aquarium
לא מגבילה את T.
בשום סוג, כולל String
.
- ב-
genericsExample()
, יש ליצור עודAquarium
, להעביר את ה-null
בשבילwaterSupply
. אםwaterSupply
הוא null, יש להדפיס"waterSupply is null"
.
fun genericsExample() {
val aquarium3 = Aquarium(null)
if (aquarium3.waterSupply == null) {
println("waterSupply is null")
}
}
- מפעילים את התוכנית ומעיינים בתוצאה.
⇒ waterSupply is null
למה כדאי לעבור את null
כשיוצרים Aquarium
? ניתן לעשות זאת, כי כברירת מחדל, T
מייצג את הסוג Any?
שניתן לביטול, הסוג שבראש היררכיית הסוגים. הטקסט הבא זהה למה שהקלדת קודם לכן.
class Aquarium<T: Any?>(val waterSupply: T)
- כדי לא להעביר את
null
, יש לבצע הסרה מפורשת שלT
מסוגAny
, על ידי הסרת?
לאחרAny
.
class Aquarium<T: Any>(val waterSupply: T)
בהקשר הזה, Any
נקרא מגבלה גנרית. כלומר, אפשר להעביר כל סוג עבור T
, כל עוד הוא לא מוגדר כ-null
.
- מה שחשוב לך הוא לוודא שניתן להעביר רק
WaterSupply
(או אחת מסיווגי המשנה שלו) עבורT
. כדי להגדיר אילוץ כללי ספציפי יותר, אפשר להחליף אתAny
ב-WaterSupply
.
class Aquarium<T: WaterSupply>(val waterSupply: T)
שלב 4: מוסיפים עוד בדיקות
בשלב זה תלמדו על הפונקציה check()
כדי לוודא שהקוד שלכם פועל כמצופה. הפונקציה check()
היא פונקציה רגילה של ספרייה בקוטלין. היא משמשת כהצהרה, ומעלמת IllegalStateException
אם הארגומנט שלה מעריך את false
.
- צריך להוסיף שיטה אחת (
addWater()
) לכיתהAquarium
כדי להוסיף מים, עםcheck()
שמוודאים שאין צורך לעבד את המים קודם.
class Aquarium<T: WaterSupply>(val waterSupply: T) {
fun addWater() {
check(!waterSupply.needsProcessing) { "water supply needs processing first" }
println("adding water from $waterSupply")
}
}
במקרה כזה, אם התנאי needsProcessing
הוא True, check()
יחריג אותו.
- ב-
genericsExample()
, יש להוסיף קוד כדי ליצורAquarium
עםLakeWater
, ואז להוסיף אליו מים.
fun genericsExample() {
val aquarium4 = Aquarium(LakeWater())
aquarium4.addWater()
}
- מפעילים את התוכנית ומקבלים חריג, כי תחילה צריך לסנן את המים.
⇒ Exception in thread "main" java.lang.IllegalStateException: water supply needs processing first at Aquarium.generics.Aquarium.addWater(Aquarium.kt:21)
- יש להוסיף שיחה כדי לסנן את המים לפני שמוסיפים אותה אל
Aquarium
. עכשיו כשמריצים את התוכנית, לא יוצאים מהכלל.
fun genericsExample() {
val aquarium4 = Aquarium(LakeWater())
aquarium4.waterSupply.filter()
aquarium4.addWater()
}
⇒ adding water from generics.LakeWater@880ec60
הנושאים שלמעלה מכסים את העקרונות הגנריים. המשימות הבאות עוסקות יותר, אבל הרעיון החשוב הוא איך להצהיר על סיווג גנרי ולהשתמש בו, אם יש מגבלה כללית.
במשימה זו, כדאי לקרוא על הסוגים הכלליים ומחוץ להם, באופן כללי. סוג של in
הוא סוג שאפשר להעביר רק לכיתה, ולא להחזיר. סוג של out
הוא סוג שאפשר להחזיר רק מכיתה.
אם בודקים את הכיתה Aquarium
, אפשר לראות שהסוג הגנרי מוחזר רק כשמקבלים את הנכס waterSupply
. אין שיטות שמשתמשות בערך מסוג T
כפרמטר (מלבד הגדרתו בבנייה). Kotlin מאפשר לך להגדיר out
סוגים בדיוק למקרה הזה, והוא יכול להסיק מידע נוסף לגבי המקום שבו הסוגים בטוחים לשימוש. באופן דומה, ניתן להגדיר in
סוגים של סוגים כלליים בלבד המועברים בשיטות בלבד, ואינם מוחזרים. ההרשאה הזו מאפשרת ל-Kotlin לבצע בדיקות נוספות לאבטחת קוד.
הסוגים in
ו-out
הם הוראות למערכות מסוג Kotlin's. מתן הסברים על כך שכל סוג הפעילות נמצא מחוץ למסגרת המחנה הזה (הוא מעורב במידה מסוימת). עם זאת, המהדר יסמן סוגים שאינם מסומנים כ-in
וגם כ-out
, לכן חשוב לדעת עליהם.
שלב 1: מגדירים סוג
- במחלקה
Aquarium
, משנים אתT: WaterSupply
לסוגout
.
class Aquarium<out T: WaterSupply>(val waterSupply: T) {
...
}
- באותו קובץ, מחוץ לכיתה, צריך להצהיר על פונקציה
addItemTo()
שצפויה להיותAquarium
מתוךWaterSupply
.
fun addItemTo(aquarium: Aquarium<WaterSupply>) = println("item added")
- התקשרות אל
addItemTo()
מ-genericsExample()
והפעלה של התוכנית.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
addItemTo(aquarium)
}
⇒ item added
קוטלין יכול לוודא שaddItemTo()
לא יבצע שום פעולה לא בטוחה עם WaterSupply
הכללי, מפני שהוא מוגדר כסוג out
.
- אם תסירו את מילת המפתח
out
, המהדר יציין שגיאה בעת התקשרות ל-addItemTo()
, מפני ש-Kotlin לא יכול לוודא שאינכם עושים פעולה לא בטוחה מסוג זה.
שלב 2: הגדרה של סוג
הסוג של in
דומה לסוג out
, אבל במקרה של סוגים כלליים שמועברים רק בפונקציות, לא מוחזרים. אם תנסה להחזיר סוג in
, תקבל שגיאת מהדר. בדוגמה הזו מגדירים סוג in
כחלק מממשק.
- ב-Aquaium.kt, מגדירים ממשק
Cleaner
שמשתמש ב-T
' שהוא מוגבל ל-WaterSupply
. הוא משמש רק כארגומנט ל-clean()
, ולכן אפשר להגדיר אותו כפרמטרin
.
interface Cleaner<in T: WaterSupply> {
fun clean(waterSupply: T)
}
- כדי להשתמש בממשק
Cleaner
, צריך ליצור מחלקהTapWaterCleaner
שמטמיעה אתCleaner
לניקויTapWater
על-ידי הוספת כימיקלים.
class TapWaterCleaner : Cleaner<TapWater> {
override fun clean(waterSupply: TapWater) = waterSupply.addChemicalCleaners()
}
- בכיתה
Aquarium
, יש לעדכן אתaddWater()
כדי לקבלCleaner
מסוגT
, ולנקות את המים לפני הוספתו.
class Aquarium<out T: WaterSupply>(val waterSupply: T) {
fun addWater(cleaner: Cleaner<T>) {
if (waterSupply.needsProcessing) {
cleaner.clean(waterSupply)
}
println("water added")
}
}
- יש לעדכן את הקוד לדוגמה של
genericsExample()
וליצורTapWaterCleaner
,Aquarium
עםTapWater
, ואז להוסיף מים באמצעות חומרי הניקוי. הוא ישתמש בחומרי ניקוי לפי הצורך.
fun genericsExample() {
val cleaner = TapWaterCleaner()
val aquarium = Aquarium(TapWater())
aquarium.addWater(cleaner)
}
Kotlin ישתמש בפרטי הסוג in
ו-out
כדי לוודא שהקוד שלך משתמש בצורה הכללית. קל לזכור את Out
ואת in
: ניתן להעביר out
סוגים כערכי החזרה, ואת in
הסוגים אפשר להעביר פנימה כארגומנטים.
כדי לקבל מידע נוסף על פתרון בעיות בסוגים ובסוגים שונים, אפשר לקרוא את התיעוד לעומק.
במשימה הזו תלמדו על פונקציות כלליות ומתי להשתמש בהן. בדרך כלל, כדאי ליצור פונקציה גנרית בכל פעם שהפונקציה מקבלת ארגומנט של מחלקה מסוג מסוים.
שלב 1: יצירת פונקציה כללית
- ב-generics/Aquaium.kt, יוצרים פונקציה
isWaterClean()
שמקבלתAquarium
. עליך לציין את הסוג הגנרי של הפרמטר. אפשרות אחת היא להשתמש במאפייןWaterSupply
.
fun isWaterClean(aquarium: Aquarium<WaterSupply>) {
println("aquarium water is clean: ${aquarium.waterSupply.needsProcessing}")
}
עם זאת, המשמעות היא ש-Aquarium
חייב לכלול פרמטר מסוג out
כדי לבצע את הפעולה הזו. לפעמים out
או in
מגבילות מדי כי צריך להשתמש בסוג גם לקלט וגם לפלט. אפשר להסיר את הדרישה out
על ידי הגדרת הפונקציה כגנרית.
- כדי להפוך את הפונקציה לגנרית, יש להציב אחרי מילת המפתח
fun
את סוגריים זוויתיים עם סוג גנריT
ועם אילוצים אחרים, במקרה הזה,WaterSupply
. יש לשנות אתAquarium
כך שההגבלה תהיה על ידיT
במקום על ידיWaterSupply
.
fun <T: WaterSupply> isWaterClean(aquarium: Aquarium<T>) {
println("aquarium water is clean: ${!aquarium.waterSupply.needsProcessing}")
}
הפרמטר T
הוא פרמטר סוג שנועד ל-isWaterClean()
המשמש לציון הסוג הגנרי של האקווריום. הדפוס הזה נפוץ מאוד, ומומלץ להקדיש כמה רגעים כדי לעבור אותו.
- צריך לקרוא לפונקציה
isWaterClean()
על ידי ציון הסוג בסוגריים מרובעים מיד אחרי שם הפונקציה ולפני הסוגריים.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
isWaterClean<TapWater>(aquarium)
}
- בשל המסקנות של הסוג מהארגומנט
aquarium
, אין צורך בסוג הזה, לכן יש להסיר אותו. מפעילים את התוכנית וצופים בפלט.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
isWaterClean(aquarium)
}
⇒ aquarium water is clean: false
שלב 2: יוצרים שיטה כללית עם סוג של תיקון
אפשר להשתמש בפונקציות גנריות גם בשיטות, גם בכיתות מהסוג שלהן. בשלב זה מוסיפים שיטה כללית ל-Aquarium
שבודקת אם יש בה סוג של WaterSupply
.
- בכיתה
Aquarium
, מצהירים על שיטהhasWaterSupplyOfType()
, שמשתמשת בפרמטר כלליR
(T
כבר בשימוש) מוגבלת ל-WaterSupply
ומחזירהtrue
אםwaterSupply
הוא מסוגR
. היא דומה לפונקציה שהצהרת עליה קודם, אבל בתוך הכיתהAquarium
.
fun <R: WaterSupply> hasWaterSupplyOfType() = waterSupply is R
- חשוב לשים לב שה
R
הסופי מודגש בקו תחתון אדום. מציבים את הסמן מעליה כדי לראות מהי השגיאה. - כדי לבצע בדיקה של
is
, עליך לומר ל-Kotlin שהסוג reled או סוג אמיתי, ושאפשר להשתמש בו בפונקציה. כדי לעשות זאת, צריך להציג אתinline
לפני מילת המפתחfun
, ואת המילהreified
לפני הסוג הגנריR
.
inline fun <reified R: WaterSupply> hasWaterSupplyOfType() = waterSupply is R
לאחר תיקון של סוג, אפשר להשתמש בו כמו סוג רגיל, כי הוא מסוג אמיתי אחרי ההטבעה. כלומר, אפשר לבצע is
בדיקות באמצעות הסוג.
אם לא משתמשים כאן ב-reified
, סוג זה לא יהיה "real" כך ש-Kotlin לא יתיר בדיקות של is
. הסיבה לכך היא שסוגים שלא תוקנו זמינים רק בזמן ההידור, ואי אפשר להשתמש בהם בזמן הריצה בתוכנית שלכם. מאמר זה מתואר בקטע הבא.
- מעבר ל-
TapWater
כסוג. כמו שמתקשרים לפונקציות גנריות, אפשר להשתמש בשיטות גנריות באמצעות סוגריים זוויתיים מהסוג שמופיע אחרי שם הפונקציה. מפעילים את התוכנית ומעיינים בתוצאה.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
println(aquarium.hasWaterSupplyOfType<TapWater>()) // true
}
⇒ true
שלב 3: יוצרים פונקציות של תוספים
אפשר להשתמש בסוגים מחודשים גם לפונקציות רגילות ולפונקציות תוספים.
- מחוץ לכיתה
Aquarium
, צריך להגדיר פונקציית תוסף ב-WaterSupply
שנקראתisOfType()
כדי לבדוק אם ה-WaterSupply
הוא מסוג ספציפי. לדוגמה:TapWater
.
inline fun <reified T: WaterSupply> WaterSupply.isOfType() = this is T
- צריך לקרוא לפונקציה של התוסף בדיוק כמו בשיטה.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
println(aquarium.waterSupply.isOfType<TapWater>())
}
⇒ true
עם פונקציות התוסף האלה, לא משנה מה סוג הAquarium
שלהן (Aquarium
או TowerTank
או סוג משנה אחר), כל עוד הוא Aquarium
. התחביר של star הקרנה הוא דרך נוחה לציין מגוון של התאמות. כשאתם משתמשים בתחזית כוכבים, קוטלין יוודא שגם אתם לא עושים דבר לא בטוח.
- כדי להשתמש בתחזית כוכבים, יש להוסיף
<*>
אחריAquarium
. יש להעביר אתhasWaterSupplyOfType()
כפונקציית תוסף, מפני שהוא לא באמת חלק מה-API הראשי שלAquarium
.
inline fun <reified R: WaterSupply> Aquarium<*>.hasWaterSupplyOfType() = waterSupply is R
- משנים את השיחה ל-
hasWaterSupplyOfType()
ומפעילים את התוכנית.
fun genericsExample() {
val aquarium = Aquarium(TapWater())
println(aquarium.hasWaterSupplyOfType<TapWater>())
}
⇒ true
בדוגמה הקודמת, היה עליך לסמן את הסוג הגנרי בתור reified
ולהגדיר את הפונקציה inline
, מפני שקוטלין צריך לדעת עליהם בזמן הריצה, ולא רק זמן הביצוע.
כל הסוגים הכלליים משמשים רק בעת ההידור של קוטלין. כך המהדר יכול לוודא שאתם עושים הכול בצורה בטוחה. בזמן ריצה כל הסוגים הגנריים נמחקים, ולכן הודעת השגיאה הקודמת לגבי בדיקת סוג שנמחק תימחק.
לאחר מכן, המהדר יכול ליצור קוד נכון בלי לשמור את הסוגים הגנריים עד לזמן הריצה. אבל לפעמים המשמעות היא שאתם עושים פעולה כלשהי, כמו is
, שבודקת את הסוגים הגנריים והמהדר לא יכול לתמוך בהם. זו הסיבה לכך שקוטלין הוסיף סוגים מאושרים או אמיתיים.
אפשר לקרוא מידע נוסף על סוגים מאומתים ומחיקת סוגים בתיעוד של Kotlin.
השיעור הזה מתמקד בתכנים גנריים, שהם חשובים יותר להפוך את הקוד לגמיש יותר ונוח יותר לשימוש חוזר.
- יצירת סיווגים כלליים שהופכים את הקוד לגמיש יותר.
- הוסיפו אילוצים כלליים כדי להגביל את הסוגים שנעשה בהם שימוש באופן כללי.
- כדאי להשתמש בסוגים
in
ו-out
באופן כללי כדי לספק בדיקת סוגים טובה יותר כדי להגביל את סוגי הכיתות שצריך להחזיר או להחזיר מהכיתות. - יש ליצור פונקציות ושיטות כלליות כדי לעבוד עם סוגים כלליים. למשל:
fun <T: WaterSupply> isWaterClean(aquarium: Aquarium<T>) { ... }
- שימוש בפונקציות גנריות כדי להוסיף לכיתה פונקציות שאינן ליבה.
- מדי פעם, יש צורך לבצע תיקון של סוגי הסיווג. סוגים שעברו עדכון, בשונה מסוגים כלליים, נמשכים לזמן ריצה.
- יש להשתמש בפונקציה
check()
כדי לוודא שהקוד פועל כמצופה. למשל:check(!waterSupply.needsProcessing) { "water supply needs processing first" }
התיעוד של Kotlin
אם אתם רוצים לקבל מידע נוסף על כל נושא בקורס הזה, או אם נתקעים, https://kotlinlang.org היא נקודת ההתחלה הטובה ביותר.
מדריכים בקוטלין
האתר https://try.kotlinlang.org כולל מדריכים עשירים בשם Kotlin Koans, מתורגמן מבוסס-אינטרנט וסדרה מלאה של מסמכי עזר עם דוגמאות.
קורס של Udacity
כדי להציג את הקורס של Udacity בנושא זה, ניתן לעיין ב-Kotlin Bootcamp for Programmers.
IntelliJ IDEA
ניתן למצוא תיעוד עבור IntelliJ IDEA באתר JetBrains.
בקטע הזה מפורטות מטלות שיעורי בית אפשריות לתלמידים שעובדים עם קוד Lab הזה, במסגרת קורס בהדרכת מורה. למורה יש אפשרות לבצע את הפעולות הבאות:
- אם צריך, מקצים שיעורי בית.
- ספרו לתלמידים איך מגישים מטלות בשיעורי בית.
- לתת ציונים למטלות שיעורי הבית.
המורים יכולים להשתמש בהצעות האלה כמה שפחות, ומומלץ להקצות להן כל שיעורי בית שדעתם מתאימה להם.
אם אתם עובדים בעצמכם על שיעור הקוד הזה, אתם מוזמנים להשתמש במטלות שיעורי הבית האלה כדי לבחון את הידע שלכם.
עונים על השאלות האלה
שאלה 1
על איזו מוסכמה למתן שם לסוג גנרי?
▬ <Gen>
▬ <Generic>
▬ <T>
▬ <X>
שאלה 2
הגבלה על סוגים מהסוגים המותרים נקראת:
הוספה של הגבלה כללית
הוספה של אילוץ כללי
▬ הבחנה
הוספה של מגבלה מסוג כללי כללית
שאלה 3
המשמעות של חידוד:
▸ מחושבים ההשפעה בפועל של אובייקט בפועל.
הוספה של מדד עם ערך מוגבל הוגדרה לכיתה.
הוספה של פרמטר הסוג הכללי הפך לסוג אמיתי.
הוספה של אינדיקטור שגיאה מרחוק הופעל.
המשך לשיעור הבא:
סקירה כללית של הקורס, כולל קישורים למעבדות קוד אחרות, זמינה במאמר "Kotlin Bootcamp for Programmers: ברוך הבא לקורס."