Menu
Coddy logo textTech

פונקציות גנריות

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Kotlin של Coddy. שיעור 37 מתוך 57.

פונקציה גנרית עובדת עם כל סוג. פרמטר הטיפוס שלה, שנכתב בתוך סוגריים זוויתיים לפני שם הפונקציה, מייצג את הטיפוס שבו משתמש הקוד שקורא לה. T הוא השם המקובל:

fun <T> firstOr(list: List<T>, default: T): T = if (list.isEmpty()) default else list[0]

בתוך main:

println(firstOr(listOf(3, 5), 0) + 1)
println(firstOr(listOf<String>(), "none").uppercase())

פלט:

4
NONE

Kotlin מסיקה את ארגומנט הטיפוס מתוך הארגומנטים. כשאין ממה להסיק אותו, כותבים אותו בעצמכם, כמו ב־listOf<String>() למעלה:

fun <T> repeatItem(item: T, times: Int): List<T> = List(times) { item }

בתוך main:

println(repeatItem("ab", 3))
println(repeatItem(7, 2))
val empty = repeatItem<Double>(1.5, 0)
println(empty)

פלט:

[ab, ab, ab]
[7, 7]
[]

לפונקציה יכולים להיות כמה פרמטרי טיפוס, ופרמטר מטיפוס פונקציה יכול להשתמש בהם. כך פועלות פונקציות ספרייה כמו map עבור כל טיפוס של איבר ותוצאה:

fun <A, B> transform(items: List<A>, f: (A) -> B): List<B> {
    val out = mutableListOf<B>()
    for (item in items) out.add(f(item))
    return out
}

fun <K, V> invert(map: Map<K, V>): Map<V, K> = map.entries.associate { (k, v) -> v to k }

בתוך main:

println(transform(listOf("kiwi", "fig")) { it.length })
println(invert(mapOf("a" to 1, "b" to 2)))

פלט:

[4, 3]
{1=a, 2=b}

פרמטר טיפוס שומר על הטיפוס של הקורא. firstOr(listOf(3, 5), 0) מחזירה Int, ולכן + 1 מתקמפל. גרסה שנכתבה עבור List<Any> הייתה מקבלת גם כל רשימה, אבל הייתה מחזירה Any ומחייבת המרה בכל קריאה:

fun firstAny(list: List<Any>, default: Any): Any = if (list.isEmpty()) default else list[0]
// firstAny(listOf(3, 5), 0) + 1               // שגיאה: ל-Any אין plus
(firstAny(listOf(3, 5), 0) as Int) + 1         // עובר הידור, אבל דורש המרת טיפוס
firstOr(listOf(3, 5), 0) + 1                   // גנרי: התוצאה היא Int
challenge icon

אתגר

קל

כתבו שתי פונקציות גנריות שעובדות עם רשימות מכל סוג. countWhere(items, predicate) מחזירה את מספר האיברים שעומדים בתנאי, פונקציה מסוג (T) -> Boolean. mostCommon(items) מחזירה את האיבר שמופיע בתדירות הגבוהה ביותר (אם יש תיקו, את האיבר שמופיע ראשון ברשימה), או null עבור רשימה ריקה.

הקוד שסופק קורא שורה של מילים ושורה של מספרים, ומדפיס את מספר המילים שאורכן עולה על 3 אותיות, את המילה השכיחה ביותר, את מספר המספרים הזוגיים, את המספר השכיח ביותר, ואת nothing: null עבור רשימה ריקה.

כתבו את הקוד שלכם בקובץ ListTools.kt. הקובץ Main.kt מכיל את קוד הקלט/פלט שסופק, ואי אפשר לערוך אותו.

נסו בעצמכם

fun main() {
    // קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
    val input = generateSequence(::readLine).toList()
    val words = input[0].split(" ")
    val numbers = input[1].split(" ").map { it.toInt() }
    println("long words: ${countWhere(words) { it.length > 3 }}")
    println("most common word: ${mostCommon(words)}")
    println("even numbers: ${countWhere(numbers) { it % 2 == 0 }}")
    println("most common number: ${mostCommon(numbers)}")
    println("nothing: ${mostCommon(listOf<String>())}")
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: Kotlin אונליין