الأصناف العامة
جزء من قسم البرمجة كائنية التوجه في رحلة Kotlin على Coddy. الدرس 38 من 57.
يمكن أن يكون للفئة معاملات نوع أيضًا. تحتوي Box<T> على قيمة من أي نوع، ويحدّد كل مثيل النوع: إذ لا تقبل Box<Int> إلا قيمًا من النوع Int:
class Box<T>(var value: T) {
fun describe() = "box with $value"
}داخل main:
val numberBox = Box(42)
val textBox = Box("hello")
numberBox.value += 1
println(numberBox.describe())
println(textBox.describe())
// numberBox.value = "x" // خطأ: الـ String ليس Intالناتج:
box with 43
box with helloتُعدّ الحاويات الفئات العامة النموذجية. يعمل تنفيذ واحد لـ Stack<T> مع كل نوع من العناصر، ويتحقق المصرّف من العناصر التي تدخل وتخرج:
class Stack<T> {
private val items = mutableListOf<T>()
val size: Int
get() = items.size
fun push(item: T) { items.add(item) }
fun pop(): T? = items.removeLastOrNull()
fun peek(): T? = items.lastOrNull()
}داخل main:
val stack = Stack<String>()
stack.push("a")
stack.push("b")
println(stack.pop())
println(stack.peek())
println(stack.size)الناتج:
b
a
1يُستنتَج وسيط النوع من وسيطات المُنشئ عند وجودها، كما في Box(42). وإلا فاكتبه: Stack<String>(). تكون المثيلات ذات وسيطات النوع المختلفة أنواعًا مختلفة، لذا لا يتم الخلط بين Stack<String> وStack<Int> مطلقًا. ويمكن لدوال الفئة العامة أيضًا إضافة معلمات نوع خاصة بها:
class Box<T>(val value: T) {
fun <R> map(f: (T) -> R): Box<R> = Box(f(value))
}داخل main:
val length = Box("kotlin").map { it.length }
println(length.value + 1)الناتج:
7تتبع الواجهات العامة القواعد نفسها. يمكن لفئة أن تنفّذ واجهة عامة، أو أن تنفّذها لنوع وسيط محدد:
interface Repository<T> {
fun add(item: T)
fun all(): List<T>
}
class MemoryRepository<T> : Repository<T> {
private val items = mutableListOf<T>()
override fun add(item: T) { items.add(item) }
override fun all() = items.toList()
}
class TagRepository : Repository<String> {
private val tags = sortedSetOf<String>()
override fun add(item: String) { tags.add(item.lowercase()) }
override fun all() = tags.toList()
}داخل main:
val ids = MemoryRepository<Int>()
ids.add(3); ids.add(1)
val tags = TagRepository()
tags.add("Kotlin"); tags.add("JVM")
println("${ids.all()} ${tags.all()}")الناتج:
[3, 1] [jvm, kotlin]التحدي
سهلاكتب الفئة العامة History<T>(limit) التي تتذكّر آخر limit من العناصر. تضيف add(item) عنصرًا وتزيل الأقدم عندما يصبح عدد العناصر أكبر من limit. تكون latest أحدث عنصر أو null، وتعيد all() العناصر من الأقدم إلى الأحدث كقائمة للقراءة فقط. ثم اكتب الامتداد History<Int>.average()، الذي يوجد فقط للسجلات التي تحتوي على أعداد، ويعيد المتوسط الصحيح للأعداد المحتفظ بها (ويعيد 0 عندما تكون فارغة).
يقرأ الكود المزوَّد الحدّ، وسطرًا من الكلمات، وسطرًا من الأعداد. ويملأ History<String> وHistory<Int>، ثم يطبع الكلمات المحتفظ بها، والكلمة الأحدث، والأعداد المحتفظ بها، ومتوسطها، وempty latest: null.
ضع الكود الخاص بك في History.kt. يحتوي Main.kt على كود الإدخال/الإخراج المزوَّد ولا يمكن تعديله.
جرّب بنفسك
fun main() {
// كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
val input = generateSequence(::readLine).toList()
val limit = input[0].toInt()
val words = History<String>(limit)
for (w in input[1].split(" ")) words.add(w)
val numbers = History<Int>(limit)
for (n in input[2].split(" ")) numbers.add(n.toInt())
println("words: ${words.all()}")
println("latest word: ${words.latest}")
println("numbers: ${numbers.all()}")
println("average: ${numbers.average()}")
println("empty latest: ${History<Char>(3).latest}")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتالمنشئات الأساسيةكتل init والتحقق من الصحةالمنشئات الثانويةمراجعة - بطاقة المكتبة4الوراثة
الأصناف المفتوحة والأصناف الفرعيةتجاوز الأعضاءsuper والمنشئاتالأصناف المجرّدةمراجعة - دليل الموظفينتدرّب بنفسك: Playground لـ Kotlin