Public get private set في Kotlin: الأخطاء والحلول

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

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

ابدأ الدورة

Public get, private set في Kotlin: كيف تتجنب الأخطاء الشائعة (وما الحل إذا وقعت فيها)

\n\n

مرحبًا، زميلي المطور! إذا كنت قد بحثت يومًا عن "Kotlin public get private set var"، فأنت لست وحدك. هذا الاستعلام من أكثر الأسئلة شيوعًا على Stack Overflow، وقد اصطدم آلاف المطورين (بما فيهم أنا سابقًا) بهذه المشكلة محاولين فهم لماذا لا يعمل الكود الخاص بهم.

\n\n

قد يبدو الأمر بسيطًا: تريد أن تكون الخاصية متاحة للجميع (public get)، ولكن فقط الفئة نفسها هي التي يمكنها تعديلها (private set). في Java، كان هذا روتينًا: تعلن عن حقل خاص (private)، وتكتب دالة getter و setter، ثم تجعل setter خاصًا. أما في Kotlin، فمن المفترض أن يكون الأمر أسهل، ولكن...

\n\n

المفاجأة: الصيغة موجودة، لكنها لا تعمل دائمًا كما تتوقع. في هذا المقال، سنستعرض أهم الأخطاء التي يقع فيها حتى المطورون المحترفون، ونوضح كيفية تجنبها. هيا بنا!

\n\n

تشريح الخاصية: var, val, get و set

\n\n

بدايةً، شرح سريع. في Kotlin، الخصائص (properties) ليست مجرد حقول. إنها عناصر كاملة يمكنها احتواء دوال getter و setter. إليك البنية الأساسية:

\n\n
var اسم_الخاصية: النوع = القيمة_الافتراضية\n    get() = field\n    set(value) { field = value }
\n\n

عند استخدام var، يقوم Kotlin تلقائيًا بإنشاء دالتي getter و setter. لكن يمكنك تغيير سلوكهما. والأهم، يمكنك تغيير مدى رؤيتهما (visibility modifiers: public, private, internal, protected).

\n\n

وهنا يبدأ الجزء المثير. لجعل getter عامًا (public) و setter خاصًا (private)، اكتب:

\n\n
var name: String = "default"\n    private set
\n\n

هل هذا كل شيء؟ تقريبًا. لكن هناك تفاصيل دقيقة تعطل هذه الآلية.

\n\n

الخطأ رقم 1: نسيان المُنشئ (Constructor)

\n\n

المشكلة الأكثر شيوعًا هي محاولة تعريف public get private set var داخل مُنشئ الفئة. على سبيل المثال:

\n\n
// ❌ خطأ: هذا غير مسموح\nclass User(public get private set var name: String)
\n\n

سيظهر خطأ في الترجمة. لماذا؟ لأن معاملات المُنشئ ليست خصائص. إنها مجرد معاملات. إذا كنت تريد خاصية مع تغيير مدى رؤية setter، يجب تعريفها داخل جسم الفئة.

\n\n

الطريقة الصحيحة:

\n\n
class User(name: String) {\n    var name: String = name\n        private set\n}
\n\n

أو، إذا كنت تستخدم data class، ستحتاج إلى حل بديل:

\n\n
data class User(private val _name: String) {\n    var name: String = _name\n        private set\n}
\n\n

نعم، data class لا يسمح بتغيير مدى رؤية setter مباشرةً للخصائص القادمة من المُنشئ الأساسي. ستحتاج إلى استخدام حقل داعم (backing field).

\n\n

الخطأ رقم 2: الخلط مع الحقل الداعم (Backing Field)

\n\n

الحقل الداعم هو حقل مخفي يقوم Kotlin بإنشائه تلقائيًا للخاصية إذا استخدمت field في getter أو setter. ولكن إذا قمت بإعادة تعريف getter أو setter دون استخدام field، فلن يتم إنشاء الحقل الداعم.

\n\n

مثال على المشكلة:

\n\n
var counter: Int = 0\n    private set\n    get() = field * 2 // ✅ هذا صحيح، field موجود
\n\n

لكن إذا كتبت:

\n\n
var counter: Int = 0\n    private set\n    get() = 42 // هذا صحيح، لكن field غير مستخدم
\n\n

في هذه الحالة، لن يتم إنشاء الحقل الداعم. وإذا حاولت استخدام field في setter، ستحصل على خطأ. الخبر الجيد: عند استخدام private set، يتم إنشاء الحقل الداعم تلقائيًا في معظم الحالات لأن setter الافتراضي يستخدم field. لكن إذا قمت بإعادة تعريف setter دون field، فاستعد للمفاجآت.

\n\n

نصيحة: استخدم دائمًا field بشكل صريح في getter و setter إذا كنت تريد العمل مع الحقل الداعم. وتذكر: إذا لم يكن للخاصية حقل داعم

المدونات

توصيات الكتب