מעבדת קוד זו היא חלק מקורס האתחול של מתכנתים בקוטלין. כדי להפיק את המקסימום מהקורס הזה, יש לפעול ברצף לפי קודי שיעור ה-Lab. בהתאם לידע שלכם, ייתכן שתוכלו לדלג על קטעים מסוימים. הקורס הזה מיועד למתכנתים בעלי שפה ממוקדת אובייקטים שרוצים ללמוד Kotlin.
מבוא
ב-Codelab הזה אתם יוצרים תוכנית Kotlin ולומדים על פונקציות ב-Kotlin, כולל ערכי ברירת מחדל לפרמטרים, למסננים, למברות ופונקציות קומפקטיות.
במקום לפתח אפליקציה לדוגמה אחת, השיעורים בקורס הזה נועדו לפתח את הידע שלכם, אך אינם תלויים זה בזה כדי שתוכלו לעיין בסעיפים שאתם מכירים. כדי לקשר ביניהם, רבות מהדוגמאות משתמשות בעיצוב של אקווריום. אם אתם רוצים לראות את הסיפור המלא באקווריום, כדאי לנסות את הקורס של מתכנתים בקוטג'ין באוניברסיטה.
דברים שחשוב לדעת
- היסודות של שפת תכנות מודרנית ומכוונת-אובייקטים
- איך לתכנת עם כיתות, שיטות וטיפול בחריגים בשפה אחת לפחות
- איך עובדים עם Kotlin's REPL (לולאה מסוג Read-Eval-Print) ב- IntelliJ IDEA
- היסודות של קוטלין, כולל סוגים, אופרטורים ולולאות
שיעור Lab זה מיועד למתכננים שיודעים שפה בעלת אובייקטים ורוצים לקבל מידע נוסף על קוטלין.
מה תלמדו
- איך ליצור תוכנית עם פונקציה
main()
וארגומנטים ב- IntelliJ IDEA - איך משתמשים בערכי ברירת מחדל ובפונקציות קומפקטיות
- איך מחילים מסננים על רשימות
- איך יוצרים למדנות בסיסיות ופונקציות ברמה גבוהה יותר
הפעולות שתבצעו:
- יש לעבוד עם REPL כדי לנסות קוד כלשהו.
- עבודה עם IntelliJ IDEA ליצירת תוכניות Kotlin בסיסיות.
במשימה הזו, אתם יוצרים תוכנית Kotlin ולומדים על הפונקציה main()
. כמו כן, יודעים איך להעביר ארגומנטים לתוכנית דרך שורת הפקודה.
אפשר לזכור את הפונקציה printHello()
שהזנת ב-REPL במעבדת קוד קודמת:
fun printHello() {
println ("Hello World")
}
printHello()
⇒ Hello World
עליך להגדיר פונקציות באמצעות מילת המפתח fun
, ולאחר מכן שם הפונקציה. בדומה לשפות תכנות אחרות, הסוגריים ()
מיועדים לארגומנטים לפונקציה, אם יש כאלה. הסוגריים המסולסלים {}
מסמנים את הקוד של הפונקציה. אין סוג החזרה לפונקציה הזו כי היא לא מחזירה דבר.
שלב 1: יצירת קובץ Kotlin
- פותחים את IntelliJ IDEA.
- בחלונית Project (פרויקט) מימין ב- IntelliJ IDEA מוצגת רשימה של הקבצים והתיקיות מהתיקייה לפרויקט. מאתרים את התיקייה src שמתחת לשלום קוטלין, ולוחצים עליה לחיצה ימנית. (אתם אמורים לקבל כבר את פרויקט שלום קוטלין ממעבדת הקוד הקודמת.)
- בוחרים באפשרות > חדש; קובץ Kotlin / כיתה.
- משאירים את הקובץ Kind כקובץ ונותן לקובץ את השם שלום.
- לוחצים על אישור.
עכשיו יש קובץ בתיקייה src שנקרא שלום.kt.
שלב 2: מוסיפים את הקוד ומפעילים את התוכנית
- כמו בשפות אחרות, הפונקציה Kotlin
main()
מציינת את נקודת הכניסה להפעלה. כל הארגומנטים בשורת הפקודה מועברים כמערך של מחרוזות.
יש להקליד או להדביק את הקוד הבא בקובץ שלום.kt:
fun main(args: Array<String>) {
println("Hello, world!")
}
בדומה לפונקציה printHello()
הקודמת, לפונקציה הזו אין הצהרה ב-return
. כל פונקציה ב-Kotlin מחזירה משהו, גם אם לא צוינה דבר באופן מפורש. לכן, פונקציה כמו main()
מחזירה פונקציה מסוג kotlin.Unit
, שהיא דרך לומר ל-Kotlin' אין ערך.
- כדי להפעיל את התוכנית, לוחצים על המשולש הירוק שמימין לפונקציה
main()
. בוחרים באפשרות Run 'helloKt' מהתפריט. - IntelliJ IDEA הידור התוכנית ומפעיל אותה. התוצאות מופיעות בחלונית יומן בחלק התחתון, כפי שמוצג למטה.
שלב 3: מעבירים ארגומנטים ל-primary()
כיוון שאתם מפעילים את התוכנית ב- IntelliJ IDEA ולא דרך שורת הפקודה, עליכם לציין את הארגומנטים בתוכנית באופן מעט שונה.
- בוחרים באפשרות Run > עריכת תצורות. החלון Run/Debug Configuration ייפתח.
- מקלידים
Kotlin!
בשדה ארגומנטים של התוכנית. - לוחצים על אישור.
שלב 4: משנים את הקוד כדי להשתמש בתבנית מחרוזת
תבנית מחרוזת מאפשרת להוסיף משתנה או ביטוי למחרוזת, והמחרוזת $
מציינת שחלק מהמחרוזת יהיה משתנה או ביטוי. הסוגריים המסולסלים {}
מוסיפים מסגרת לביטוי, אם יש כאלה.
- בקטע שלום.kt, שנה את הודעת הפתיחה כדי להשתמש בארגומנט הראשון שהועבר לתוכנית,
args[0]
, במקום"world"
.
fun main(args: Array<String>) {
println("Hello, ${args[0]}")
}
- מריצים את התוכנית, והפלט כולל את הארגומנט שצוין.
⇒ Hello, Kotlin!
במשימה הזו אפשר להבין למה כמעט לכל דבר בקוטלין יש ערך, ולמה זה שימושי.
לחלק מהשפות האחרות יש הצהרות, שהן שורות קוד שאין להן ערך. בקוטלין, כמעט כל ביטוי הוא ביטוי ויש לו ערך – גם אם הערך הזה הוא kotlin.Unit
.
- ב-שלום.kt, כותבים קוד ב-
main()
כדי להקצותprintln()
למשתנה שנקראisUnit
ומדפיסים אותו. (println()
לא מחזירה ערך, כך שהיא מחזירהkotlin.Unit
).
// Will assign kotlin.Unit
val isUnit = println("This is an expression")
println(isUnit)
- מפעילים את התוכנית.
println()
הראשון ידפיס את המחרוזת"This is an expression"
.println()
השני מדפיס את הערך של הצהרתprintln()
הראשונה, כלומרkotlin.Unit
.
⇒ This is an expression kotlin.Unit
- יש להצהיר על
val
בשםtemperature
ולאתחל אותו ל-10. - יש להצהיר על
val
נוסף בשםisHot
ולהקצות את ערך החזרה של הצהרתif
/else
אלisHot
, כפי שמוצג בקוד הבא. מאחר שהוא ביטוי, אפשר להשתמש בערך של הביטויif
באופן מיידי.
val temperature = 10
val isHot = if (temperature > 50) true else false
println(isHot)
⇒ false
- שימוש בערך של ביטוי בתבנית מחרוזת. מוסיפים קוד כדי לבדוק את הטמפרטורה כדי לקבוע אם הדג בטוח או חם מדי, ואז להפעיל את התוכנית.
val temperature = 10
val message = "The water temperature is ${ if (temperature > 50) "too warm" else "OK" }."
println(message)
⇒ The water temperature is OK.
במשימה הזו מקבלים מידע נוסף על הפונקציות ב-Kotlin, ועוד על ביטוי התנאי המועיל ביותר ב-when
.
שלב 1: יצירת פונקציות מסוימות
בשלב זה מלמדים חלק מהתכנים שלמדתם ויוצרים פונקציות עם סוגים שונים. אפשר להחליף את התוכן של שלום.kt בקוד החדש הזה.
- צריך לכתוב פונקציה בשם
feedTheFish()
כדי להתקשר אלrandomDay()
כדי לקבל יום אקראי בשבוע. אפשר להשתמש בתבנית מחרוזת כדי להדפיסfood
כדי שהדגים יאכלו באותו יום. נכון לעכשיו, הדגים אוכלים את אותו האוכל בכל יום.
fun feedTheFish() {
val day = randomDay()
val food = "pellets"
println ("Today is $day and the fish eat $food")
}
fun main(args: Array<String>) {
feedTheFish()
}
- צריך לכתוב את הפונקציה
randomDay()
כדי לבחור יום אקראי ממערך ולהחזיר אותו.
הפונקציה nextInt()
מגבילה את המספר השלם שמגביל את המספר מ-Random()
עד 6 כדי להתאים למערך week
.
fun randomDay() : String {
val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday")
return week[Random().nextInt(week.size)]
}
- הפונקציות
Random()
ו-nextInt()
מוגדרות ב-java.util.*
. בחלק העליון של הקובץ, מוסיפים את הייבוא הנדרש:
import java.util.* // required import
- מפעילים את התוכנית ובודקים את הפלט.
⇒ Today is Tuesday and the fish eat pellets
שלב 2: שימוש בביטוי מתי
כדי להרחיב את ההגדרה, אפשר לשנות את הקוד ולבחור אוכל אחר עבור ימים שונים באמצעות ביטוי מסוג when
. ההצהרה when
דומה ל-switch
בשפות תכנות אחרות, אבל when
מפסיקה באופן אוטומטי בסוף כל סניף. הוא גם מוודא שהקוד מכסה את כל הסניפים אם אתם בודקים ערך enum.
- ב-שלום.kt, מוסיפים פונקציה בשם
fishFood()
שמקבלת יום כ-String
ומחזירה את המאכל ליום הדגים כString
. יש להשתמש ב-when()
, כך שבכל יום הדגים יקבלו אוכל מסוים. מפעילים את התוכנית כמה פעמים כדי לראות פלטים שונים.
fun fishFood (day : String) : String {
var food = ""
when (day) {
"Monday" -> food = "flakes"
"Tuesday" -> food = "pellets"
"Wednesday" -> food = "redworms"
"Thursday" -> food = "granules"
"Friday" -> food = "mosquitoes"
"Saturday" -> food = "lettuce"
"Sunday" -> food = "plankton"
}
return food
}
fun feedTheFish() {
val day = randomDay()
val food = fishFood(day)
println ("Today is $day and the fish eat $food")
}
⇒ Today is Thursday and the fish eat granules
- יש להוסיף סניף המוגדר כברירת מחדל לביטוי
when
באמצעותelse
. כדי לוודא שברירת המחדל תילקח לפעמים לתוכנית, יש להסיר את הסניפיםTuesday
ו-Saturday
.
השימוש בברירת המחדל מבטיח שהערך שלfood
יקבל ערך לפני ההחזרה, כך שאין צורך לאתחל אותו. כי הקוד מקצה עכשיו מחרוזת ל-food
רק פעם אחת, ולכן אפשר להצהיר עלfood
באמצעותval
במקוםvar
.
fun fishFood (day : String) : String {
val food : String
when (day) {
"Monday" -> food = "flakes"
"Wednesday" -> food = "redworms"
"Thursday" -> food = "granules"
"Friday" -> food = "mosquitoes"
"Sunday" -> food = "plankton"
else -> food = "nothing"
}
return food
}
- מאחר שלכל ביטוי יש ערך, אפשר לנסח את הקוד בצורה תמציתית יותר. מחזירים את הערך של הביטוי
when
ישירות ומבטלים את המשתנהfood
. הערך של הביטויwhen
הוא הערך של הביטוי האחרון של הסניף שעמד בתנאי.
fun fishFood (day : String) : String {
return when (day) {
"Monday" -> "flakes"
"Wednesday" -> "redworms"
"Thursday" -> "granules"
"Friday" -> "mosquitoes"
"Sunday" -> "plankton"
else -> "nothing"
}
}
הגרסה הסופית של התוכנית נראית בערך כך:
import java.util.* // required import
fun randomDay() : String {
val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday")
return week[Random().nextInt(week.size)]
}
fun fishFood (day : String) : String {
return when (day) {
"Monday" -> "flakes"
"Wednesday" -> "redworms"
"Thursday" -> "granules"
"Friday" -> "mosquitoes"
"Sunday" -> "plankton"
else -> "nothing"
}
}
fun feedTheFish() {
val day = randomDay()
val food = fishFood(day)
println ("Today is $day and the fish eat $food")
}
fun main(args: Array<String>) {
feedTheFish()
}
במשימה הזו תלמדו על ערכי ברירת מחדל של פונקציות ושיטות. אפשר גם ללמוד על פונקציות קומפקטיות, שיכולות להפוך את הקוד שלכם תמציתי וקריא יותר, ובכך להפחית את מספר נתיבי הקוד לבדיקה. פונקציות קומפקטיות נקראות גם פונקציות ביטוי יחיד.
שלב 1: יוצרים ערך ברירת מחדל לפרמטר
ב-Kotlin, אפשר להעביר ארגומנטים לפי שם הפרמטר. אפשר גם לציין ערכי ברירת מחדל לפרמטרים: אם הארגומנט מקבל את הערך' הוא משתמש בערך ברירת המחדל. מאוחר יותר, כשכותבים שיטות (פונקציות לחברים), אפשר להימנע מכתיבת גרסאות רבות של אותה שיטה בעומס יתר.
- ב-שלום.kt, כותבים פונקציה
swim()
עם פרמטרString
בשםspeed
שמדפיס את מהירות הדגים. לפרמטרspeed
יש ערך ברירת מחדל של"fast"
.
fun swim(speed: String = "fast") {
println("swimming $speed")
}
- מהפונקציה
main()
, יש לקרוא לפונקציהswim()
שלוש דרכים. צריך קודם לקרוא לפונקציה באמצעות ברירת המחדל. אחר כך קוראים לפונקציה ומעבירים את הפרמטרspeed
ללא שם, ואז קוראים לפונקציה באמצעות שם הפרמטרspeed
.
swim() // uses default speed
swim("slow") // positional argument
swim(speed="turtle-like") // named parameter
⇒ swimming fast swimming slow swimming turtle-like
שלב 2: מוסיפים את הפרמטרים הנדרשים
אם לא מציינים ברירת מחדל לפרמטר, תמיד צריך להעביר את הארגומנט המתאים.
- ב-שלום.kt, כותבים פונקציה
shouldChangeWater()
שמשתמשת בשלושה פרמטרים:day
,temperature
ורמהdirty
. הפונקציה מחזירה אתtrue
אם יש לשנות את המים, מה שקורה אם יום ראשון, אם הטמפרטורה גבוהה מדי או אם המים מלוכלכים מדי. היום בשבוע נדרש, אבל טמפרטורת ברירת המחדל היא 22 והרמה המלוכלכת כברירת מחדל היא 20.
יש להשתמש בביטויwhen
ללא ארגומנט, שמוגדר ב-Kotlin כסדרת בדיקות שלif/else if
.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
return when {
temperature > 30 -> true
dirty > 30 -> true
day == "Sunday" -> true
else -> false
}
}
- יש להתקשר אל
shouldChangeWater()
מ-feedTheFish()
ולציין את היום. לפרמטרday
אין ברירת מחדל, לכן צריך לציין ארגומנט. בשני הפרמטרים האחרים שלshouldChangeWater()
יש ערכי ברירת מחדל, כך שאין צורך להעביר ארגומנטים עבורם.
fun feedTheFish() {
val day = randomDay()
val food = fishFood(day)
println ("Today is $day and the fish eat $food")
println("Change water: ${shouldChangeWater(day)}")
}
=> Today is Thursday and the fish eat granules Change water: false
שלב 3: פונקציות קומפקטיות
הביטוי when
שכתבת בשלב הקודם מכיל הרבה היגיון בכמות קטנה של קוד. אם אתם רוצים לפתוח את החבילה קצת יותר בקלות, או אם התנאים לבדיקה הם מורכבים יותר, אתם יכולים להשתמש במשתנים מקומיים ידועים. אבל הדרך שבה נעשה זאת היא פונקציות קומפקטיות.
פונקציות קומפקטיות או פונקציות ביטוי יחיד הן תבנית נפוצה ב-Kotlin. כשפונקציה מחזירה את התוצאות של ביטוי יחיד, אפשר לציין את גוף הפונקציה אחרי סמל =
, להשמיט את הסוגריים המסולסלים {}
ולהשמיט את return
.
- ב-שלום.kt, מוסיפים פונקציות קומפקטיות כדי לבדוק את התנאים.
fun isTooHot(temperature: Int) = temperature > 30
fun isDirty(dirty: Int) = dirty > 30
fun isSunday(day: String) = day == "Sunday"
- יש לשנות את
shouldChangeWater()
כדי להפעיל את הפונקציות החדשות.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
return when {
isTooHot(temperature) -> true
isDirty(dirty) -> true
isSunday(day) -> true
else -> false
}
}
- מפעילים את התוכנית. הפלט מ-
println()
עםshouldChangeWater()
צריך להיות זהה לפלט לפני המעבר לשימוש בפונקציות קומפקטיות.
ערכי ברירת מחדל
ערך ברירת המחדל של הפרמטר לא חייב להיות ערך. היא יכולה להיות פונקציה אחרת, כפי שהיא מופיעה בדגימה החלקית הבאה:
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = getDirtySensorReading()): Boolean {
...
במשימה הזו אנחנו לומדים קצת על המסננים בקוטלין. מסננים הם דרך יעילה לקבל חלק מרשימה מסוימת בהתאם לתנאי מסוים.
שלב 1: יצירת מסנן
- בקטע שלום.kt, מגדירים רשימה של קישוטי אקווריום ברמה העליונה באמצעות
listOf()
. אפשר להחליף את התוכן ב-שלום.kt.
val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
- יש ליצור פונקציה חדשה מסוג
main()
עם שורה, כדי להדפיס רק את האותות שמתחילים באות &33;p'. הקוד של תנאי המסנן נמצא בסוגריים מסולסלים{}
, והמאפייןit
מתייחס לכל פריט כאשר המסנן עובר בלופ. אם הביטוי מחזיר אתtrue
, הפריט נכלל.
fun main() {
println( decorations.filter {it[0] == 'p'})
}
- מריצים את התוכנית ומשתמשים בפלט הבא בחלון הפעלה:
⇒ [pagoda, plastic plant]
שלב 2: משווים בין מסננים נלהבים לבין מסננים אבובים
אם אתם מכירים את המסננים בשפות אחרות, יכול להיות שתהיו אם המסננים בקוטלין ניכרים או פאזלים. האם רשימת התוצאות נוצרת באופן מיידי, או כשמתבצעת גישה לרשימה? ב-Kotlin, זה קורה בכל דרך שתרצו. כברירת מחדל, filter
הוא נלהב, ובכל פעם שמשתמשים במסנן, נוצרת רשימה.
כדי שהמסנן יהיה איטי, אפשר להשתמש ברכיב Sequence
. זהו אוסף שיכול לראות רק פריט אחד בכל פעם, החל מההתחלה ולפני הסוף. לנוחותכם, זהו בדיוק ה-API שמסנן אבובים זקוק לו.
- בקטע שלום.kt, משנים את הקוד כדי להקצות את הרשימה המסוננים למשתנה שנקרא
eager
, ואז מדפיסים אותו.
fun main() {
val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
// eager, creates a new list
val eager = decorations.filter { it [0] == 'p' }
println("eager: " + eager)
- מתחת לקוד, הערך את המסנן באמצעות
Sequence
עםasSequence()
. מקצים את הרצף למשתנה בשםfiltered
ומדפיסים אותו.
// lazy, will wait until asked to evaluate
val filtered = decorations.asSequence().filter { it[0] == 'p' }
println("filtered: " + filtered)
כשמחזירים את תוצאות המסנן כ-Sequence
, המשתנה filtered
לא יכלול רשימה חדשה – הוא ירכיב Sequence
של רכיבי הרשימה ואת הידע של המסנן שיש להחיל על הרכיבים האלה. בכל גישה לרכיבים של Sequence
, המסנן מיושם והתוצאה מוחזרת אליך.
- יש לאלץ הערכה של הרצף על ידי המרתו ל-
List
עםtoList()
. מדפיסים את התוצאה.
// force evaluation of the lazy list
val newList = filtered.toList()
println("new list: " + newList)
- מפעילים את התוכנית וצופים בפלט.
⇒ eager: [pagoda, plastic plant] filtered: kotlin.sequences.FilteringSequence@386cc1c4 new list: [pagoda, plastic plant]
כדי לראות תצוגה חזותית של מה שקורה בSequence
ולהערכה מדורגת, אפשר להשתמש בפונקציה map()
. הפונקציה map()
מבצעת שינוי פשוט בכל רכיב ברצף.
- עם אותה רשימת
decorations
שלמעלה, יש לבצע טרנספורמציה עםmap()
שלא עושה דבר, פשוט להחזיר את הרכיב שהועבר. צריך להוסיףprintln()
כדי להציג בכל פעם שמתבצעת גישה לרכיב, ולהקצות את הרצף למשתנה שנקראlazyMap
.
val lazyMap = decorations.asSequence().map {
println("access: $it")
it
}
- הדפסה של
lazyMap
הרכיב הראשון שלlazyMap
באמצעותfirst()
, והדפסה שלlazyMap
שהומרו למכשירList
.
println("lazy: $lazyMap")
println("-----")
println("first: ${lazyMap.first()}")
println("-----")
println("all: ${lazyMap.toList()}")
- מפעילים את התוכנית וצופים בפלט. הדפסת
lazyMap
רק מודפסת על האסמכתה שלSequence
– לא מתבצעת קריאה ל-println()
הפנימי. הדפסת הרכיב הראשון ניגשת רק לרכיב הראשון. המרתSequence
ל-List
ניגשת לכל הרכיבים.
⇒ lazy: kotlin.sequences.TransformingSequence@5ba23b66 ----- access: rock first: rock ----- access: rock access: pagoda access: plastic plant access: alligator access: flowerpot all: [rock, pagoda, plastic plant, alligator, flowerpot]
- צריך ליצור
Sequence
חדש באמצעות המסנן המקורי לפני החלתmap
. מדפיסים את התוצאה.
val lazyMap2 = decorations.asSequence().filter {it[0] == 'p'}.map {
println("access: $it")
it
}
println("-----")
println("filtered: ${ lazyMap2.toList() }")
- מפעילים את התוכנית וצופים בפלט הנוסף. בדומה לקבלת הרכיב הראשון,
println()
הפנימי נקרא רק עבור הרכיבים שאליהם מתבצעת גישה.
⇒ ----- access: pagoda access: plastic plant filtered: [pagoda, plastic plant]
במשימה הזו, תקבלו מבוא ללמבדות ולפונקציות ברמה גבוהה יותר בקוטלין.
למבדס
בנוסף לפונקציות בעלות שם מסורתי, קוטלין תומך בלמדמות. lambda הוא ביטוי שיוצר פונקציה. אבל במקום הצהרה על פונקציה בעלת שם, אתם מצהירים על פונקציה שאין לה שם. אחד היתרונות של הקטע הזה הוא שאפשר להעביר את הביטוי lambda כנתונים. בשפות אחרות, למורים יש שמות פונקציות אנונימיות, ליטרות של פונקציות או שמות דומים.
פונקציות ברמה גבוהה יותר
כדי ליצור פונקציה בסדר גבוה יותר, צריך להעביר למדה לפונקציה אחרת. במשימה הקודמת, יצרת פונקציה בסדר גבוה יותר בשם filter
. עברת אל ביטוי ה-lamba הבא אל filter
בתור התנאי לבדיקה:{it[0] == 'p'}
באופן דומה, הפונקציה map
היא סדר גבוה יותר, והלמדה שהעברתם אליה הייתה הטרנספורמציה שתחול.
שלב 1: מידע על למדות
- בדומה לפונקציות בעלות שם, ב-lambdas יכולים להיות פרמטרים. כשמדובר ב-lambdas, הפרמטרים (והסוגים שלהם, אם יש צורך) מופיעים מימין למה שנקרא חץ פונקציה
->
. הקוד שצריך להריץ מופיע משמאל בחץ הפונקציה. אחרי שמקצים את למבדה למשתנה, אפשר להפעיל אותו כמו פונקציה.
אפשר להשתמש ב-REPL (כלים > Ktlin > Kotlin REPL), ולנסות את הקוד הבא:
var dirtyLevel = 20
val waterFilter = { dirty : Int -> dirty / 2}
println(waterFilter(dirtyLevel))
⇒ 10
בדוגמה הזו, למבדה מקבלת Int
בשם dirty
, ומחזירה dirty / 2
. (מאחר שסינון מסיר לכלוך).
- התחביר של Kotlin'לסוגי הפונקציות קשור מאוד לתחביר שלו עבור lambdas. השתמשו בתחביר הזה כדי להצהיר בבירור על משתנה שכולל פונקציה:
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }
כך כתוב הקוד:
- יוצרים משתנה בשם
waterFilter
. waterFilter
יכול להיות כל פונקציה שמקבלתInt
ומחזירהInt
.- אפשר להקצות למדה ל-
waterFilter
. - המבדה מחזירה את ערך הארגומנט
dirty
חלקי 2.
לתשומת ליבכם, אין צורך לציין יותר את סוג הארגומנט של למדה. הסוג מחושב לפי הסקת סוג.
שלב 2: יוצרים פונקציה בסדר גבוה יותר
עד עכשיו, הדוגמאות של למדאות נראות בעיקר כפונקציות. הכוח האמיתי של הלמבאס משתמש בהן כדי ליצור פונקציות ברמה גבוהה יותר, כשהארגומנט לפונקציה היא פונקציה אחרת.
- צריך לכתוב פונקציה בסדר גבוה יותר. זוהי דוגמה בסיסית לפונקציה שמקבלת שני ארגומנטים. הארגומנט הראשון הוא מספר שלם. הארגומנט השני הוא פונקציה שמקבלת מספר שלם ומחזירה מספר שלם. אפשר לנסות אותו ב-REPL.
fun updateDirty(dirty: Int, operation: (Int) -> Int): Int {
return operation(dirty)
}
גוף הקוד קורא לפונקציה שהועברה כארגומנט השני ומעביר אליו את הארגומנט הראשון.
- כדי לקרוא לפונקציה הזו צריך להעביר אותה כמספר שלם ולפונקציה.
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }
println(updateDirty(30, waterFilter))
⇒ 15
הפונקציה שצריך להעביר לא חייבת להיות למדה; היא יכולה להיות פונקציה רגילה בעלת שם. כדי לציין את הארגומנט כפונקציה רגילה, השתמש באופרטור ::
. כך קודין יודע שאתם מעבירים את ההפניה לפונקציה כארגומנט, ולא מנסים לקרוא לפונקציה.
- יש לנסות להעביר פונקציה בעלת שם רגיל אל
updateDirty()
.
fun increaseDirty( start: Int ) = start + 1
println(updateDirty(15, ::increaseDirty))
⇒ 16
var dirtyLevel = 19;
dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}
println(dirtyLevel)
⇒ 42
- כדי ליצור קובץ מקור מסוג Kotlin ב- IntelliJ IDEA, צריך להתחיל בפרויקט Kotlin.
- כדי להדר ולהפעיל תוכנית ב- IntelliJ IDEA, לוחצים על המשולש הירוק לצד הפונקציה
main()
. הפלט מופיע בחלון היומן שבהמשך. - ב- IntelliJ IDEA, צריך לציין ארגומנטים בשורת הפקודה שיש להעביר לפונקציה
main()
ב-Run > עריכת הגדרות. - כמעט לכל דבר בקוטלין יש ערך. אפשר להשתמש בעובדה זו כדי להפוך את הקוד שלך לתמציתי יותר על ידי שימוש בערך של
if
או שלwhen
כביטוי או כערך החזרה. - ארגומנטים המוגדרים כברירת מחדל מסירים את הצורך בכמה גרסאות של פונקציה או שיטה. למשל:
fun swim(speed: String = "fast") { ... }
- פונקציות קומפקטיות או פונקציות עם ביטוי יחיד יכולות להפוך את הקוד שלכם לקריא יותר. למשל:
fun isTooHot(temperature: Int) = temperature > 30
- למדת כמה מידע בסיסי על מסננים, שמשתמשים בביטויים מסוג למדה. למשל:
val beginsWithP = decorations.filter { it [0] == 'p' }
- ביטוי lambda הוא ביטוי שיוצר פונקציה ללא שם. ביטויי למבדה מוגדרים בין סוגריים מסולסלים
{}
. - בפונקציה עם סדר גבוה יותר, אתם מעבירים פונקציה כמו ביטוי למבדה לפונקציה אחרת כנתונים. למשל:
dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}
יש הרבה דברים בשיעור הזה, בייחוד אם אתם חדשים בלמדד. שיעור מאוחר יותר חוזר בין למדנות ופונקציות ברמה גבוהה יותר.
התיעוד של Kotlin
אם אתם רוצים לקבל מידע נוסף על כל נושא בקורס הזה, או אם נתקעים, https://kotlinlang.org היא נקודת ההתחלה הטובה ביותר.
- תבניות מחרוזת
- ביטוי מסוג
when
- פונקציות ביטוי יחיד
- פונקציות ולמדמות בסדר גבוה
- מסננים
- רצפים
- תחביר שיחה אחרונה של פרמטרים
מדריכים בקוטלין
האתר https://try.kotlinlang.org כולל מדריכים עשירים בשם Kotlin Koans, מתורגמן מבוסס-אינטרנט וסדרה מלאה של מסמכי עזר עם דוגמאות.
קורס של Udacity
כדי להציג את הקורס של Udacity בנושא זה, ניתן לעיין ב-Kotlin Bootcamp for Programmers.
IntelliJ IDEA
ניתן למצוא תיעוד עבור IntelliJ IDEA באתר JetBrains.
בקטע הזה מפורטות מטלות שיעורי בית אפשריות לתלמידים שעובדים עם קוד Lab הזה, במסגרת קורס בהדרכת מורה. למורה יש אפשרות לבצע את הפעולות הבאות:
- אם צריך, מקצים שיעורי בית.
- ספרו לתלמידים איך מגישים מטלות בשיעורי בית.
- לתת ציונים למטלות שיעורי הבית.
המורים יכולים להשתמש בהצעות האלה כמה שפחות, ומומלץ להקצות להן כל שיעורי בית שדעתם מתאימה להם.
אם אתם עובדים בעצמכם על שיעור הקוד הזה, אתם מוזמנים להשתמש במטלות שיעורי הבית האלה כדי לבחון את הידע שלכם.
מענה על השאלות האלה
שאלה 1
הפונקציה contains(element: String)
מחזירה true
אם המחרוזת element
כלולה במחרוזת שהיא מופעלת. מהו הפלט של הקוד הבא?
val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
println(decorations.filter {it.contains('p')})
▬ [pagoda, plastic, plant]
▬ [pagoda, plastic plant]
▬ [pagoda, plastic plant, flowerpot]
▬ [rock, alligator]
שאלה 2
בהגדרת הפונקציה הבאה, איזה פרמטר נדרש?fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20, numDecorations: Int = 0): Boolean {...}
▬ numDecorations
▬ dirty
▬ day
▬ temperature
שאלה 3
אפשר להעביר פונקציה רגילה בעלת שם (לא תוצאה של הקריאה לפונקציה) לפונקציה אחרת. איך תעביר/י את increaseDirty( start: Int ) = start + 1
אל updateDirty(dirty: Int, operation: (Int) -> Int)
?
▬ updateDirty(15, &increaseDirty())
▬ updateDirty(15, increaseDirty())
▬ updateDirty(15, ("increaseDirty()"))
▬ updateDirty(15, ::increaseDirty)
המשך לשיעור הבא:
סקירה כללית של הקורס, כולל קישורים למעבדות קוד אחרות, זמינה במאמר "Kotlin Bootcamp for Programmers: ברוך הבא לקורס."