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

Kotlin / السلوك القابل للاستخدام والحدود المنمطة / الدرس 10

استخدام الامتدادات ودوال النطاق مع مستقبل واضح

افهم اختيار الامتداد وفق النوع المعلن، وفروق المستقبل والقيمة المعادة بين let وrun وwith وapply وalso.

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

أهداف الدرس

  • توقّع الامتداد الذي سيُختار استنادا إلى نوع المستقبل المعلن.
  • اختر دالة النطاق وفقا لقيمة ردها ووضوح السياق الذي تنشئه.

يضيف الامتداد صياغة استدعاء ولا يضيف عضوا للصنف

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

افصل اختيار الامتداد عن تجاوز الأعضاء

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

kotlin اختيار الامتداد بحسب النوع المعلن
open class Base
class Derived : Base()
fun Base.label(): String = "base extension"
fun Derived.label(): String = "derived extension"
fun main() {
    val value: Base = Derived()
    println(value.label())
    println(Derived().label())
}
الناتج المتوقع
base extension
derived extension

المخرج المتوقع base extension ثم derived extension. لا يحدد كائن وقت التشغيل وحده الاستدعاء الأول. هذا مصدر كامل توضيحي لم يُترجم هنا.

اقرأ شكل المستقبل وقيمة الرد معا

تعرض let وalso كائن السياق كمعامل، غالبا باسم it، بينما تعرض run وwith وapply الكائن كمستقبل، غالبا عبر this. تعيد let وrun وwith نتيجة الكتلة، وتعيد apply وalso كائن السياق نفسه. ينبغي أن توجه هذه الفروق اختيارك. تُستخدم apply كثيرا لتهيئة كائن، وalso لملاحظة إضافية، وlet لتحويل قيمة؛ لكنها أعراف وليست قيودا مفروضة. لا تتحقق دالة النطاق من الخلو بذاتها؛ بل يتحكم استدعاء آمن مثل value?.let في تشغيل الكتلة عندما تكون قيمة المستقبل قابلة للخلو.

لا تستبدل الكائن بنتيجة الكتلة دون قصد

يستخدم مثال البناء apply للاحتفاظ بـStringBuilder أثناء إضافة النص، ثم let لحساب طوله. قد يغير استبدال apply بـrun نوع الرد المستنتج إذا لم تفحص آخر تعبير. يجب أن يظل واضحا أي قيمة تنتقل إلى الخطوة التالية من السلسلة. وإذا احتاجت السلسلة this وit متداخلتين، فقدّم متغيرا محليا مسمى أو دالة مساعدة، بدلا من إجبار القارئ على إعادة بناء عدة مستقبلات ضمنية. الوضوح جزء من الواجهة؛ ولا يكفي توفير أسماء متغيرات قليلة لتبرير حجب الحالة التي تُعدَّل.

kotlin دوال نطاق تعيد الكائن وأخرى تعيد نتيجة الكتلة
fun main() {
    val builder = StringBuilder().apply {
        append("seat")
        append("-1")
    }
    val length = builder.let { text -> text.length }
    val observed = builder.also { text -> println(text.toString()) }
    println(length)
    println(observed === builder)
}
الناتج المتوقع
seat-1
6
true

المخرجات المتوقعة هي seat-1 ثم 6 ثم true. تطبع also النص وتعيد مرجع الباني نفسه، بينما تعيد let العدد الصحيح الذي يمثل الطول. لم يُنفّذ برنامج Kotlin في البيئة.

قد يوضح الامتداد ذو المستقبل الخالي معنى الغياب

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

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

يعمل امتداد Base لكائن Derived على غير المتوقع.

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

تعيد سلسلة نطاق Unit حيث كان المطلوب كائنا.

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

تعدّل النطاقات المتداخلة مستقبلا غير مقصود.

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

اختبر فهمك

1. أي دالة نطاق تختار لتهيئة كائن ثم إعادة الكائن نفسه؟

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

تعد apply اختيارا معتادا عندما يكون أسلوب التهيئة بالمستقبل واضحا. وتستطيع also الاحتفاظ بالكائن مع استخدام معامل صريح. اختر حسب وضوح الشيفرة، لا بمجرد اتباع العادة. تعيد run وlet نتيجة الكتلة، ولذلك تتطلبان تحليلا مقصودا لآخر تعبير إذا استُخدمتا لهذه المهمة.

2. هل تستطيع إضافة امتداد تجاوز عضو موجود في الصنف؟

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

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

أهم ما تعلمته

  • تستخدم الامتدادات نوع المستقبل المعلن وحدود الدوال العادية.
  • اختر دوال النطاق على أساس وضوح المستقبل والقيمة التي تعيدها.

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