المنشئ الفارغ في data class في Kotlin: 5 أخطاء وكيفية إصلاحها

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

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

ابدأ الدورة

مقدمة: لماذا لا يريد data class أن يكون فارغًا؟

\n\n

هل سبق لك أن حاولت إنشاء data class في Kotlin لتطبيق Android ووجدت بدهشة أن المترجم يرفض قبول المنشئ الفارغ؟ إذا كان الأمر كذلك، فأنت لست وحدك. هذا السؤال جمع آلاف المشاهدات على Stack Overflow، مما يعني أن مئات المطورين (من المبتدئين إلى الخبراء) تعثروا بنفس المشكلة.

\n\n

لماذا يحدث هذا؟ السبب هو أن data class في Kotlin ليس مجرد فئة لتخزين البيانات. فهو يُنشئ تلقائيًا دوال equals() و hashCode() و toString() و copy() و componentN(). ولكل هذا السحر، يحتاج إلى منشئ أساسي (primary constructor) يحتوي على معامل واحد على الأقل. بدونه، لا يمكن.

\n\n

في هذه المقالة، سنحلل أهم 5 أخطاء يرتكبها المطورون عند محاولة إنشاء منشئ فارغ لـ data class في Kotlin Android، وسنوضح كيفية تجنبها. هيا بنا!

\n\n

الخطأ رقم 1: الإعلان المباشر عن منشئ فارغ

\n\n

الخطأ الأكثر شيوعًا هو محاولة كتابة شيء مثل:

\n\n
// ❌ هذا غير مسموح!\ndata class User {\n    constructor() : this() // خطأ في الترجمة\n}\n
\n\n

يطلب Kotlin بشدة أن يتم الإعلان عن المنشئ الأساسي في رأس الفئة. إذا حاولت إنشاء منشئ ثانوي بدون معاملات يستدعي نفسه، فستحصل على استدعاء ذاتي لا نهائي و خطأ في الترجمة.

\n\n

الحل: القيم الافتراضية

\n\n

أبسط وأفضل طريقة هي تعيين قيم افتراضية لجميع معاملات المنشئ الأساسي:

\n\n
// ✅ صحيح: قيم افتراضية\ndata class User(\n    val name: String = "",\n    val age: Int = 0,\n    val email: String = ""\n)\n\n// الآن يمكنك إنشاء كائن بدون وسائط\nval emptyUser = User()\nprintln(emptyUser) // User(name=, age=0, email=)\n
\n\n

هذا الأسلوب يعمل "مباشرة" ولا يتطلب أي إضافات أو تعليقات توضيحية إضافية. تحصل على منشئ فارغ كامل، ويتم تهيئة جميع الحقول بالقيم الافتراضية.

\n\n

الخطأ رقم 2: تجاهل متطلبات المكتبات (Room, Retrofit, Gson)

\n\n

تتطلب العديد من مكتبات Android وجود منشئ فارغ لإنشاء الكائنات عبر الانعكاس (reflection). المثال الكلاسيكي هو Room:

\n\n
// ❌ Room سيعطي خطأ\n@Entity\ndata class User(\n    @PrimaryKey val id: Int,\n    val name: String,\n    val age: Int\n)\n
\n\n

عند محاولة استخدام data class مع Room، ستحصل على استثناء: Cannot instantiate User using no-arg constructor. تحدث مشاكل مماثلة مع Gson و Retrofit عند إلغاء تسلسل JSON.

\n\n

الحل: القيم الافتراضية + الأنواع القابلة للصفر (nullable)

\n\n

بالنسبة لـ Room، يكفي إضافة قيم افتراضية:

\n\n
// ✅ Room سعيد\n@Entity\ndata class User(\n    @PrimaryKey val id: Int = 0,\n    val name: String = "",\n    val age: Int = 0\n)\n
\n\n

بالنسبة لـ Gson و Retrofit، غالبًا ما يكون من الأسهل استخدام الأنواع القابلة للصفر:

\n\n
// ✅ للعمل مع JSON\ndata class ApiResponse(\n    val status: String? = null,\n    val data: List<Item>? = null\n)\n
\n\n

ولكن كن حذرًا: الأنواع القابلة للصفر قد تؤدي إلى استثناء المؤشر الفارغ (NPE) إذا نسيت التحقق من القيمة. استخدمها بوعي.

\n\n

الخطأ رقم 3: نسيان إضافة إضافة Kotlin No-Arg

\n\n

أحيانًا لا تكون القيم الافتراضية مناسبة. على سبيل المثال، إذا كنت تستخدم Jackson للتسلسل وتحتاج إلى أنواع محددة بدون nullable. في هذه الحالة، تأتي إضافة kotlin-noarg للإنقاذ.

\n\n

يعتقد العديد من المطورين خطأً أنه يكفي فقط إضافة التبعية في ملف build.gradle. ولكن بدون الإعداد الصحيح، لن تعمل الإضافة.

\n\n

الحل: الإعداد الصحيح لـ No-Arg

\n\n

أضف الإضافة في ملف build.gradle.kt

المدونات

توصيات الكتب