إسقاط النجمة ومتى تستخدم *
طبّق إسقاط النجمة للأنواع العامة غير المعروفة وتعرّف على حدوده.
إسقاط النجمة ومتى تستخدم * درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ما إسقاط النجمة؟
إسقاط النجمة (*) هو طريقة Kotlin للتعبير عن «نوع عام ذي معامل نوع غير معروف». وهو البديل الآمن للنوع الخام في Java أو للبدل غير المقيّد <?>.
fun printList(list: List<*>) {
for (item in list) println(item)
}
fun main() {
printList(listOf(1, 2, 3))
printList(listOf("a", "b"))
printList(listOf(true, 42, "mixed"))
}القراءة من الأنواع ذات إسقاط النجمة
من List<*> يمكنك قراءة العناصر على أنها Any?. ولا يمكنك إضافة عناصر لأن النوع الفعلي غير معروف.
fun process(list: List<*>) {
val first: Any? = list.firstOrNull()
println("First: $first, Size: ${list.size}")
// list.add("x") // compile error: can't write to List<*>
}
fun main() {
process(listOf(10, 20, 30))
}النجمة مقابل out Any
إن List<*> وList<out Any?> متكافئان. وإسقاط النجمة اختصار للإسقاط المتغاير مع الحد العلوي.
fun sumStars(list: List<*>): Int = list.size
fun sumOut(list: List<out Any?>): Int = list.size
fun main() {
val l = listOf(1, "two", true)
println(sumStars(l)) // 3
println(sumOut(l)) // 3
}النجمة في معاملات الدوال
استخدم * في تواقيع الدوال عندما تحتاج إلى قبول أي صيغة عامة، لكنك لا تستدعي إلا الدوال التي لا تتطلب معرفة T.
fun containerInfo(map: Map<*, *>): String {
return "keys=${map.keys.size}, values=${map.values.size}"
}
fun main() {
val m = mapOf(1 to "one", 2 to "two")
println(containerInfo(m))
}النجمة مع MutableList
بالنسبة إلى MutableList<*>، يمكنك القراءة على أنها Any?، لكن لا يمكنك الكتابة إليها إطلاقًا — إذ يمنع المترجم ذلك.
fun clearFirstElement(list: MutableList<*>) {
if (list.isNotEmpty()) {
list.removeAt(0) // OK: remove by index doesn't need T
// list.add("x") // Error: can't write unknown type
}
}
fun main() {
val m = mutableListOf(1, 2, 3)
clearFirstElement(m)
println(m) // [2, 3]
}فئة مع إسقاط النجمة
عند التحقق من نوع فئة عامة أثناء التشغيل، استخدم إسقاط النجمة لأن معاملات الأنواع تُحذف.
fun isListOfSomething(obj: Any): Boolean {
return obj is List<*> // OK with star
// obj is List<String> // Warning: cannot check erased type
}
fun main() {
println(isListOfSomething(listOf(1, 2))) // true
println(isListOfSomething("not a list")) // false
}معاملات نجمة متعددة
يمكن أن تحتوي الدالة على معاملات متعددة ذات إسقاط نجمة عند التعامل مع أزواج أو خرائط ذات أنواع غير معروفة.
fun describeMap(map: Map<*, *>) {
map.forEach { (k, v) ->
println("${k?.javaClass?.simpleName} -> ${v?.javaClass?.simpleName}")
}
}
fun main() {
describeMap(mapOf("key" to 42, 1 to true))
}متى لا تستخدم النجمة
تجنّب إسقاط النجمة عندما تحتاج إلى الكتابة في مجموعة، أو عندما يمكنك استخدام معامل نوع مقيّد بدلًا منه — فالمعامل المقيّد يوفر معلومات أكثر.
// Bad: loses type information
fun addToStar(list: MutableList<*>, item: Any?) {
// list.add(item) // compile error
}
// Better: use bounded type parameter
fun <T : Any> addTyped(list: MutableList<T>, item: T) {
list.add(item)
}
fun main() {
val l = mutableListOf("a")
addTyped(l, "b")
println(l)
}النجمة مع فحوصات الأنواع والتحويلات
استخدم إسقاط النجمة لإجراء فحوصات instanceof على الفئات العامة، ثم حوّل النوع إلى نوع محدد لتنفيذ العمل الفعلي.
fun handleResponse(response: Any) {
if (response is List<*>) {
val list = response as List<*>
println("List with ${list.size} elements")
val first = list.firstOrNull()
if (first is String) println("First string: $first")
}
}
fun main() {
handleResponse(listOf("hello", "world"))
handleResponse(42)
}تطبيقي: موزّع الأحداث العام
موزّع يقبل أي Handler<*>، لكنه يوزّع الأحداث محددة النوع بأمان.
interface Handler<in T> { fun handle(event: T) }
class LogHandler : Handler<Any> {
override fun handle(event: Any) = println("Event: $event")
}
fun dispatch(handler: Handler<*>, event: Any) {
@Suppress("UNCHECKED_CAST")
(handler as Handler<Any>).handle(event)
}
fun main() {
dispatch(LogHandler(), "click")
dispatch(LogHandler(), 42)
}النجمة في سياقات Reified
يشيع استخدام إسقاط النجمة خصوصًا في شيفرة الانعكاس والتسلسل، حيث يُفحَص نوع التشغيل عبر KClass<*>.
fun printClassName(klass: kotlin.reflect.KClass<*>) {
println(klass.simpleName)
}
fun main() {
printClassName(String::class) // String
printClassName(List::class) // List
printClassName(Int::class) // Int
}اختبار سريع
ما النوع الذي تحصل عليه عند القراءة من List<*>؟
مراجعة
يقبل إسقاط النجمة (*) أي صيغة عامة للوصول للقراءة فقط. استخدمه لفحوصات الأنواع والأدوات العامة والانعكاس. وتجنّبه عندما تحتاج إلى الكتابة في مجموعة أو عندما يوفر معامل نوع مقيّد أمانًا أفضل للأنواع.
تعلم Kotlin مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 51
- الدروس
- 203
الأسئلة الشائعة
هل درس «إسقاط النجمة ومتى تستخدم *» مجاني؟
نعم — نص درس «إسقاط النجمة ومتى تستخدم *» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «إسقاط النجمة ومتى تستخدم *»؟
طبّق إسقاط النجمة للأنواع العامة غير المعروفة وتعرّف على حدوده. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «إسقاط النجمة ومتى تستخدم *»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الدوال العامة وقيود الأنواع باستخدام where
- التباين في موضع التصريح: in وout
- إسقاط النجمة ومتى تستخدم *
- محو النوع ومعاملات النوع reified