Generics في Kotlin: لماذا تحتاجها وكيف تستخدمها

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة إلى Generics في Kotlin



Generics (الأنواع العامة) هي إحدى الميزات الرئيسية للغات البرمجة ذات الأنواع الثابتة، بما في ذلك Kotlin. إنها تسمح بكتابة كود مرن وقابل لإعادة الاستخدام يعمل مع أنواع مختلفة من البيانات، مع الحفاظ على أمان صارم للأنواع في مرحلة التجميع.



تخيل أنك بحاجة إلى إنشاء بنية بيانات لتخزين قائمة من العناصر. بدون generics، سيتعين عليك كتابة فئات منفصلة لكل نوع (IntList، StringList، UserList). مع generics، تكفي فئة واحدة MyList<T> ستعمل مع أي نوع.



// بدون Generics — يجب تكرار الكودclass IntList(private val items: MutableList<Int>)class StringList(private val items: MutableList<String>)

// مع Generics — فئة واحدة لجميع الأنواعclass GenericList<T>(private val items: MutableList<T>) { fun add(item: T) { items.add(item) } fun get(index: Int): T = items[index]}


في هذه المقالة، سنشرح بالتفصيل كيفية عمل generics في Kotlin، وسننظر في تركيبها، وحالات استخدامها، والمفاهيم المتقدمة مثل التباين المشترك والتباين المعاكس.



أساسيات العمل مع Generics



إعلان الفئات والوظائف العامة



لإعلان فئة عامة، يكفي تحديد معامل نوع واحد أو أكثر بين قوسين زاويتين بعد اسم الفئة:



class Box<T>(var value: T) {    fun getValue(): T = value    fun setValue(newValue: T) { value = newValue }}

// الاستخدامval intBox = Box<Int>(42)val stringBox = Box<String>("Hello")

// Kotlin يمكنه استنتاج النوع، لذا يمكن الكتابة بشكل أقصرval anotherBox = Box("Auto type inference")


يمكن أن تكون الوظائف عامة أيضًا. يتم تحديد معامل النوع قبل اسم الوظيفة:



fun <T> printItem(item: T) {    println("Item: $item")}

fun <T> createPair(first: T, second: T): Pair<T, T> { return Pair(first, second)}

// الاستخدامprintItem(123)printItem("Text")val pair = createPair("A", "B")


قيود الأنواع (Type Bounds)



في بعض الأحيان، تحتاج إلى تقييد الأنواع التي يمكن استخدامها في generics. لهذا، تُستخدم الحدود العليا (upper bounds) مع الكلمة المفتاحية : Type:



// فقط الأنواع التي تطبق Comparablefun <T : Comparable<T>> findMax(a: T, b: T): T {    return if (a > b) a else b}

// قيود متعددة باستخدام wherefun <T> processItem(item: T) where T : CharSequence, T : Comparable<T> { println("Length: ${item.length}") println("Compared: ${item.compareTo(item)}")}

// الاستخدامprintln(findMax(10, 20)) // 20println(findMax("Apple", "Banana")) // "Banana"// findMax(10, "Text") // خطأ في التجميع!


التباين: in, out وإسقاط الأنواع



واحدة من أصعب الموضوعات ولكنها مهمة في generics هي التباين (variance). إنها تحدد كيفية ارتباط الأنواع العامة ببعضها البعض عند الوراثة.



التباين الثابت (الافتراضي)



افتراضيًا، تكون generics في Kotlin ثابتة التباين. هذا يعني أن Box<Number> و Box<Int> ليسا نوعين فرعيين من بعضهما البعض، حتى لو كان Int نوعًا فرعيًا من Number:



val intBox: Box<Int> = Box(42)// val numBox: Box<Number> = intBox // خطأ في التجميع!


التباين المشترك (out)



المعدل out يجعل النوع متباينًا بشكل مشترك. هذا يعني أن Box<Int> يصبح نوعًا فرعيًا من Box<Number>. يُستخدم عندما يتم استخدام النوع T فقط في المواضع الخارجة (قيم الإرجاع):



class Producer<out T>(private val item: T) {    fun produce(): T = item  // T فقط في الخرج}                

المدونات

توصيات الكتب