Reified في Kotlin: سحر الأدوية الجنسية للمبتدئين

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

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

ابدأ الدورة

ما هو reified في Kotlin ولماذا هو "سحر"؟

\n

إذا كنت قد كتبت بلغة Java من قبل، فبالتأكيد واجهت Type Erasure — محو الأنواع أثناء التنفيذ. في Java (وفي Kotlin افتراضيًا) تكون معلومات النوع داخل الأدوية الجنسية متاحة فقط في مرحلة التجميع، وتختفي في وقت التشغيل. هذا يعني أنه لا يمكنك كتابة if (value is T) أو T::class داخل دالة عادية، لأن T أثناء التنفيذ هو مجرد Object.

\n

لكن Kotlin ذهب أبعد من ذلك. الكلمة المفتاحية reified (من الإنجليزية "مُجسَّد") تسمح لك "بإحياء" النوع داخل دالة inline. بفضل reified يمكنك فعل ما كان يبدو مستحيلًا في Java: التحقق من النوع، الحصول على KClass، إنشاء مثيلات، وحتى العمل مع الانعكاس — وكل ذلك في وقت التشغيل.

\n

في هذه المقالة، سنشرح كيف يعمل reified بأمثلة حقيقية يمكنك تطبيقها فورًا. هيا بنا!

\n\n

المشكلة: Type Erasure في العمل

\n

تخيل: أنت تكتب دالة يجب أن تتحقق مما إذا كان الكائن عبارة عن سلسلة نصية. محاولة ساذجة:

\n
fun <T> isString(value: Any): Boolean {\n    return value is T // خطأ في التجميع!\n}
\n

سيصدر المترجم خطأ: "Cannot check for instance of erased type: T". لماذا؟ لأنه أثناء التنفيذ، لا تعرف JVM ما هو T. بالنسبة لها، T هو مجرد Object.

\n

نفس الشيء مع الحصول على الكلاس: T::class داخل دالة عادية لن يعمل أيضًا. هذا هو Type Erasure — الصداع الرئيسي لمطوري Java.

\n\n

الحل: reified + inline

\n

يقدم Kotlin مخرجًا أنيقًا. "لتذكر" النوع في وقت التشغيل، يجب جعل الدالة inline ووضع علامة على معامل النوع بالكلمة المفتاحية reified:

\n
inline fun <reified T> isString(value: Any): Boolean {\n    return value is T // الآن يعمل!\n}
\n

الآن يمكنك الاستدعاء:

\n
println(isString<String>("Hello")) // true\nprintln(isString<Int>("Hello"))    // false
\n

كيف يعمل هذا؟ عندما تضع علامة على دالة كـ inline، يقوم المترجم بتضمين كودها مباشرة في مكان الاستدعاء. و reified تجبر المترجم على استبدال النوع المحدد (مثل String) بدلاً من T في الكود المُنشأ. ونتيجة لذلك، يظهر في البايت كود تحقق صريح value is String.

\n\n

أمثلة عملية لاستخدام reified

\n

دعنا نلقي نظرة على بعض السيناريوهات الحقيقية حيث يبسط reified الحياة حقًا.

\n\n

1. الحصول على الكلاس في وقت التشغيل

\n

واحدة من أكثر المهام شيوعًا هي الحصول على KClass أو Class من معامل النوع. بدون reified هذا مستحيل:

\n
inline fun <reified T> getKClass(): KClass<T> = T::class\n\n// الاستخدام:\nval kClass = getKClass<String>()\nprintln(kClass.simpleName) // String
\n

هذا مفيد بشكل خاص عند العمل مع مكتبات تتطلب الانعكاس (مثل التسلسل، ORM، حاويات DI).

\n\n

2. إنشاء مثيل حسب النوع

\n

هل تريد إنشاء كائن من النوع المطلوب دون تمرير المُنشئ؟ بسهولة:

\n
inline fun <reified T : Any> createInstance(): T {\n    return T::class.createInstance()\n}\n\n// مثال:\nval instance = createInstance<StringBuilder>()\ninstance.append("Hello, reified!")
\n

لكن كن حذرًا: createInstance() يعمل فقط إذا كان للكلاس مُنشئ بدون معاملات. وإلا ستحصل على استثناء.

\n\n

3. التصفية حسب النوع في المجموعات

\n

لنفترض أن لديك قائمة من كائنات من أنواع مختلفة، وتريد تصفية السلاسل النصية فقط. في المكتبة القياسية لـ Kotlin يوجد filterIsInstance<T>()، لكن يمكنك بسهولة كتابة نسختك الخاصة:

\n


                
                

المدونات

توصيات الكتب