Nullable في Kotlin: كيفية التعامل مع القيم null بدون ألم؟ دليل كامل

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

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

ابدأ الدورة

ما الذي يخفيه علامة الاستفهام؟ نغوص في nullable في Kotlin

\n\n

هل سبق لك أن كتبت كودًا بلغة Java وأصبت بـ NullPointerException في أكثر الأوقات غير المناسبة؟ إذا كان الأمر كذلك - فأنت تعلم كم هو مؤلم. لقد حل مطورو Kotlin هذه المشكلة مرة واحدة وإلى الأبد، وجعلوا null safety ليس مجرد ميزة، بل فلسفة للغة. لكن المبتدئين غالبًا ما يخافون من السؤال: "In Kotlin, what is the idiomatic way to deal with nullable values, referencing or converting them?" (هكذا بالضبط يبدو السؤال الأكثر شيوعًا على Stack Overflow).

\n\n

اليوم سنشرح جميع اصطلاحات التعامل مع nullable: من ?. البسيط إلى let الذكي و !! السحري. والأهم من ذلك - سننظر تحت الغطاء لنفهم كيف يعمل هذا على مستوى البايت كود. هيا بنا!

\n\n

نبذة تعريفية سريعة: ما هو nullable؟

\n\n

في Kotlin، تنقسم الأنواع إلى معسكرين: nullable (يمكن أن تكون null) و non-nullable (لا يمكن). إذا كتبت var name: String = null - سيصدر المترجم خطأ. أما var name: String? = null - فهو مقبول. علامة الاستفهام هي علامة تقول: "مرحبًا أيها المترجم، أعلم أنه قد يكون هناك قيمة فارغة هنا، فلا تغضب".

\n\n

ولكن كيف نتعامل مع هذا؟ مجرد التحقق من null باستخدام if - هذا ممل وليس بطريقة Kotlin. دعنا نلقي نظرة على الأدوات الحقيقية.

\n\n

الثلاثي المنقذ: ?. و ?: و ?.

\n\n

تقدم Kotlin ثلاثة أركان يقوم عليها كل التعامل مع nullable. احفظها - ستوفر لك ساعات من التصحيح.

\n\n

1. عامل الاستدعاء الآمن (?.)

\n\n

هذا هو الضيف الأكثر شيوعًا في كودك. يسمح لك عامل safe call باستدعاء دالة أو خاصية فقط إذا كان الكائن لا يساوي null. إذا كان الكائن null - سيعيد العامل قيمة null، ولن يحدث أي استثناء.

\n\n
val user: User? = null\nval name: String? = user?.name  // name = null, لا يوجد خطأ
\n\n

تحت الغطاء، يتحول هذا إلى بايت كود يقوم بفحص عادي للـ null واستدعاء شرطي. لا سحر، فقط أمان.

\n\n

2. عامل Elvis (?:)

\n\n

Elvis هو صديقك عندما تحتاج إلى تعيين قيمة افتراضية. إذا كان الجزء الأيسر ليس null - نأخذه، وإلا - نأخذ ما على اليمين.

\n\n
val name: String? = null\nval displayName: String = name ?: "ضيف"  // "ضيف"
\n\n

يمكن استخدام Elvis أيضًا للخروج المبكر من الدالة:

\n\n
fun getUserName(user: User?): String {\n    val name = user?.name ?: return "مجهول"\n    return name\n}
\n\n

3. تأكيد عدم الصفرية (!!)

\n\n

هذا هو العامل المتمرد. إنه يقول: "أنا متأكد أنه ليس null هنا، ومستعد للموت (بمعنى، إلقاء NPE) إذا كنت مخطئًا". استخدمه بحذر، فقط عندما تكون متأكدًا 100%.

\n\n
val user: User? = getUserFromDatabase() // نحن متأكدون من وجوده\nval name: String = user!!.name
\n\n

تحت الغطاء، يتم ترجمة !! إلى فحص عادي مع إلقاء NullPointerException عند وجود null. لا شيء معقد، ولكنه خطير.

\n\n

الطريقة الاصطلاحية: let, run, apply ورفاقهم

\n\n

الآن ننتقل إلى الجزء الأكثر إثارة للاهتمام. السؤال على Stack Overflow يدور حول هذا بالضبط: كيفية تحويل القيم nullable بشكل اصطلاحي. الإجابة هي دوال الإضافة من المكتبة القياسية.

\n\n

let - ملك تحويلات nullable

\n\n

تقوم الدالة let بتنفيذ كتلة من الكود فقط إذا كان الكائن ليس null. داخل الكتلة، يكون الكائن متاحًا كـ it (أو يمكن إعادة تسميته).

\n\n
val user: User? = getUser()\nuser?.let { \n    println("اسم المستخدم: ${it.name}")\n    // هنا it - مضمون أنه ليس null\n}
\n\n

هذه هي الطريقة الاصطلاحية لتنفيذ إجراء فقط عندما تكون القيمة غير null. بدون let، كان علينا كتابة:

\n\n
if (user != null) {\n    println("اسم المستخدم: ${user.name}")\n}

المدونات

توصيات الكتب