محتويات الدورة
Kotlin
أسس اللغة والحالة الصريحة
السلوك القابل للاستخدام والحدود المنمطة
التزامن والتكامل والتصميم المترابط

Kotlin / أسس اللغة والحالة الصريحة / الدرس 2

التعبير عن القرارات والدوال القابلة لإعادة الاستخدام

استخدم تعبيرات if وwhen، والمجالات والحلقات، والمعاملات المسماة، وعقود الدوال الصريحة.

وقت القراءة التقريبي: 5 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • اختر نتائج مكتملة لجميع الفروع وحدود دوال يسهل فهمها.
  • ميّز حدود مجال التكرار، والقيمة الافتراضية للمعامل، والأثر الجانبي للدالة.

يمكن للفرع أن ينتج قيمة

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

رتّب الشروط وفق القاعدة المقصودة

تختار when التي لا تحمل موضوعا أول شرط يُقيَّم إلى true، ولذلك تحتاج الشروط المتداخلة إلى ترتيب مقصود. في المثال، السعة السالبة غير صالحة، والصفر يعني الامتلاء، وما عداه من أعداد موجبة يعني الإتاحة. يغطي else الأعداد المتبقية. ولو سبق شرط واسع مثل remaining >= 0 شرط الصفر، فقد يصبح فرع الامتلاء غير قابل للوصول. اختبر الحدود باستخدام عدد سالب والصفر والواحد قبل إضافة حالات عادية كثيرة؛ فهذه الأمثلة تكشف أخطاء المتباينات التي قد لا تظهر في تشغيل واحد للمسار الناجح.

kotlin تصنيف كامل باستخدام الفروع
fun capacityLabel(remaining: Int): String = when {
    remaining < 0 -> "invalid"
    remaining == 0 -> "full"
    else -> "available"
}

fun main() {
    for (value in listOf(-1, 0, 1)) {
        println(capacityLabel(value))
    }
}
الناتج المتوقع
invalid
full
available

المخرجات المتوقعة، بالترتيب، هي invalid ثم full ثم available. لا تعدّل الدالة معاملها ولا تستشير خدمة حجز. لم يُنفّذ البرنامج هنا، لأن أدوات Kotlin غير متوفرة.

اجعل حدود التكرار صريحة

يشمل المجال المغلق 1..3 طرفيه. أما المجال نصف المفتوح 0 until size فيستبعد size، ويفيد للتكرار على الفهارس الصالحة؛ ومع ذلك يكون المرور المباشر على العناصر أوضح عندما لا تحتاج الفهرس. تعبّر downTo وstep عن التكرار التنازلي أو ذي الخطوات المتباعدة. تجنب زيادة الفهرس يدويا ما لم تحتج الخوارزمية إلى تلك الحالة. تخرج break من أقرب حلقة، بينما تنتقل continue إلى التكرار التالي منها. تحتاج الحلقات المتداخلة إلى تسمية واضحة أو إعادة تنظيم خاصة، لأن الخروج من موضع غير مناسب قد يتجاوز عملا مطلوبا بصمت.

وضّح الاستدعاء بالمعاملات المسماة والافتراضية

توفّر القيمة الافتراضية قيمة عندما يغفل المستدعي ذلك المعامل؛ وهي ليست إعدادا عاما خفيا. وتساعد المعاملات المسماة على تمييز قيم متجاورة من النوع نفسه. تحسب الدالة في المثال تسمية محلية دون أثر خارجي. تجنب المعامل المنطقي الذي لا يفهم القارئ معناه عند الاستدعاء إلا بفتح تصريح الدالة؛ فقد تستحق الأنماط المتعددة تعدادا أو دوال منفصلة. أعد Unit عندما لا تنتج الدالة قيمة ذات معنى، وميّز بين قيمة تُطبع وقيمة تعيدها الدالة للمستدعي ليستعملها.

kotlin قيم افتراضية ومعاملات مسماة ومجال مغلق
fun badge(name: String, prefix: String = "Guest"): String {
    return "$prefix: $name"
}

fun main() {
    println(badge("Mira"))
    println(badge(name = "Salim", prefix = "Member"))
    println((1..3).sum())
}
الناتج المتوقع
Guest: Mira
Member: Salim
6

الأسطر المتوقعة هي Guest: Mira ثم Member: Salim ثم 6. يستخدم الاستدعاء الأول البادئة الافتراضية، ويستبدلها الثاني صراحة، ويشمل المجال العدد ثلاثة عند جمعه. هذه مخرجات متوقعة، وليست نتائج تشغيل مرصودة.

أبق افتراضات المدخل قريبة من حد الدالة

يخبر توقيع الدالة المترجم بأنواع القيم، لكنه لا يعبّر تلقائيا عن كل قيد في المجال. فقد يكون Int سالبا، بينما يشترط عدد المقاعد قيمة غير سالبة. حدّد هل سترفض المدخل أم تطبّعه أم تمثّل عدم صلاحيته صراحة، واجعل المستدعي يعرف ذلك الاختيار. افصل الحساب الصرف عن الطباعة والإدخال، حتى تُفحص السياسة بقيم ثابتة. تقدم الدروس اللاحقة require والنتائج القابلة للخلو والنتائج المغلقة؛ ويعتمد الاختيار بينها على كون المدخل الخاطئ إساءة برمجية من المستدعي أو حالة خارجية متوقعة.

الأخطاء الشائعة وإصلاحها

يُتجاوز العنصر الصالح الأخير.

لماذا يحدث؟
استُخدم حد مستبعد حيث كان المقصود مجالا يشمل النهاية.
كيف تصلحه؟
اكتب القيم التي يجب أن يشملها التكرار، ثم اختر صياغة المجال المطابقة لها.
كيف تتجنب تكراره؟
افحص المدخل الفارغ والعنصر الواحد وحد النهاية الأخير.

يحجب شرط when واسع فرعا أكثر تحديدا.

لماذا يحدث؟
يُنفّذ أول شرط مطابق، فلا يصل التدفق إلى الفرع اللاحق المتداخل معه.
كيف تصلحه؟
أعد ترتيب الشروط أو اجعلها متنافية بحيث لا تتداخل معانيها.
كيف تتجنب تكراره؟
اختبر حالات الحدود بين كل شرطين متجاورين.

يتلقى المستدعي Unit بدلا من العدد المطلوب.

لماذا يحدث؟
طبعت الدالة الناتج ولم تعده بوصفه قيمة يمكن استخدامها.
كيف تصلحه؟
أعد نتيجة الحساب، واترك الطباعة عند حد المستدعي المسؤول عن العرض.
كيف تتجنب تكراره؟
صرّح بأنواع الرد صراحة عند الحدود المهمة للدوال.

اختبر فهمك

1. كيف تصنّف الصفر على أنه ممتلئ قبل التعامل مع السعة الموجبة؟

اعرض الحل المشروح

استخدم فرعا خاصا بالصفر يتبعه فرع للموجب، مع فرع صريح يرفض السالب؛ أو استخدم ترتيب المثال الذي يعالج السالب ثم الصفر ثم الباقي. افحص -1 و0 و1. ليست الصياغة وحدها هي المهمة، بل اكتمال المعنى وعدم تداخله عند الحدود.

2. أعد كتابة دالة تطبع المجموع فقط بحيث تستطيع دالة أخرى إعادة استخدام ناتجها.

اعرض الحل المشروح

عرّف fun sum(a: Int, b: Int): Int = a + b، ثم استدع println(sum(2, 3)) عند حد العرض. تنتج الدالة القابلة لإعادة الاستخدام الآن بيانات، بدلا من الاقتصار على أثر الطباعة في الطرفية. تبقى افتراضات المجال والتجاوز العددي جزءا من عقد الحساب؛ فإرجاع القيمة لا يزيل هذه الالتزامات.

أهم ما تعلمته

  • تجعل فروع التعبيرات والحدود الصريحة القرارات قابلة للمراجعة.
  • يجب أن تميّز الدالة بوضوح بين البيانات المعادة والآثار الجانبية.

المراجع الرسمية