تعلّم البرمجة بلغة كوتلن (33): المصفوفات Arrays ومعامل vararg

تعلّم البرمجة بلغة كوتلن (33): المصفوفات Arrays ومعامل vararg
أستمع الى المقال

شرحنا في الدروس السابقة، التجميعات في كوتلن، مثل القوائم Lists، والأطقم Sets، والخرائط Maps. في هذا الدرس، سنتحدث عن المصفوفات Arrays وكيفية استخدامها.

ما هي المصفوفات Arrays:

تعتبر المصفوفة مجموعة من العناصر من نوع بيانات واحد، يتم تخزينها في الذاكرة بطريقة متسلسلة. فمثلًا، عندما نحتاج إلى التعامل مع قيم متعددة من نفس نوع البيانات، يمكننا حفظها معًا في مصفوفة كوحِدة واحدة. 

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

توضح الصورة أدناه مصفوفة من خمسة عناصر. وهي عبارة عن أرقام من نوع البيانات عدد بفاصلة عشرية Double:

كما نرى في الصورة، يمتلك كل عنصر فهرس Index خاص به يتكون من أعداد صحيحة تبدأ من الصفر (0-4). نستخدم الفهرس المقابل لكل عنصر، للوصول إليه والتعامل معه. يكون فهرس العنصر الأول دائمًا الرقم 0، بينما يكون فهرس العنصر الأخير حجم size (عدد العناصر) المصفوفة ناقص 1.

إنشاء مصفوفة بعناصر محددة:

يمكن في كوتلن إنشاء مصفوفات تحتوي على عناصر من أنواع البيانات الأساسية باستخدام هذه الأنواع:

IntArray, LongArray, DoubleArray, FloatArray, CharArray, ShortArray, ByteArray, BooleanArray.

لإنشاء مصفوفة من النوع Int نستخدم النوع IntArray، ومن النوع Long نستخدم النوع LongArray، وهكذا. ما عدا نوع البيانات String، والذي لا يتوفر له نوع خاص به. ولكن بالطبع يمكننا إنشاء عناصر مصفوفة من النوع String كما سنرى لاحقًا في هذا الدرس.

دوال خاصة بكل نوع بيانات:

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

  • ()intArray نستخدم هذه الدالة في إنشاء مصفوفة من النوع IntArray.
  • ()doubleArray نستخدم هذه الدالة في إنشاء مصفوفة من النوع DoubleArray.
  • ()charArray نستخدم هذه الدالة في إنشاء مصفوفة من النوع CharArray.
  • وهكذا لكل الأنواع الأساسية أعلاه، ما عدا النوع String.

كمثال، فلنلقي نظرة على الشفرة التالية:

عند استخدام الدوال المحددة لكل نوع بيانات، يجب أن تكون عناصر المصفوفة من هذا النوع. بالتالي السطر التالي سينتج خطأ:

val array1 = intArrayOf(18.0, 2.5, 21.3, 1.7, 10.9, 7.4)

ﻷننا استخدمنا دالة ()intArray المخصصة لنوع البيانات Int، لإنشاء مصفوفة تحتوي على عناصر من نوع البيانات Double.

استخدام دالة ()arrayOf:

رأينا في الفقرة أعلاه، كيف يمكننا إنشاء مصفوفة من نوع بيانات محدد. أما إذا كنا نريد إنشاء مصفوفة من النوع String أو حتى صنف خاص بنا، نستخدم الدالة ()arrayOf، والتي تستقبل أي نوع بيانات وتعيد مصفوفة تحتوي على عناصر من هذا النوع:

val fruits = arrayOf(“Orange”, “Apple”, “Banana”, “Mango”, “Avocado”)

وﻷن كل العناصر التي تم إرسالها للدالة ()arrayOf عبارة عن كائنات من نوع البيانات String، سيكون نوع بيانات المتغير fruits هو <Array<String. أي أنه يُمثّل مصفوفة من نوع البيانات String. وهذا ما يظهر عند وضع مؤشر الماوس على المتغير في برنامج IntelliJ:

خصائص ودوال:

نستخدم الخاصية size مع المصفوفة، لمعرفة عدد العناصر. ودالة ()get أو أقواس الفهرس المربعة [ ]، لإعادة قيمة العنصر باستخدام فهرسه. ودالة ()set أو أيضًا أقواس الفهرس المربعة [ ] و علامة الإسناد =، لتغيير قيمة العنصر. يمكننا تطبيق كل ذلك في شفرة لفهمه أكثر:

استخدمنا دالة ()joinToString لنتمكن من طباعة عناصر المصفوفة بطريقة نصية مفهومة أكثر. وللحصول على آخر عنصر في المصفوفة، استخدمنا الخاصية size التي تعيد عدد عناصر المصفوفة وأنقصنا من الناتج واحد. سيكون العائد هو فهرس العنصر الأخير، لذا وضعناه مباشرة في في أقواس الفهرس المربعة.

وستكون نتيجة الطباعة:

يمكن إيجاد كل الخصائص والدوال التي يمكننا استخدامها مع Array، في هذا الرابط من موقع كوتلن الرسمي.

استقبال قيم غير محدودة في الدالة:

عند استخدام الدوال: intArrayOf، أو doubleArrayOf، …الخ. أو حتى الدالة ()arrayOf، نرسل لهم قيم غير محددة العدد، وستنشئ لنا مصفوفة بعدد الكائنات التي أرسلناها إليهم، كما رأينا في الأمثلة أعلاه. 

ولكننا تعلمنا في درس الدوال، أننا نضع عدد محدود من المعاملات بين قوسي الدالة، ثم عند استدعاء الدالة لن نستطيع أن نرسل لها قيم أكثر من عدد معاملاتها. إذا كيف تستقبل هذه الدوال، عدد غير محدود من القيم؟

لفهم ذلك، دعونا ننظر إلى المعامل الذي تستقبله دالة ()intArray:

عند وضع مؤشر الماوس على الدالة ()intArray في برنامج IntelliJ، تظهر نافذة بها معلومات إضافية عن الدالة:

public fun intArrayOf(vararg elements: Int): IntArray

دالة كوتلن عادية تبدأ بمحدد وصول عام public، وتستقبل معامل اسمه elements من نوع البيانات Int مسبوق بالكلمة المفتاحية vararg، وتعيد قيمة من النوع IntArray. درسنا كل ذلك في دروس سابقة في هذه الدورة، ما عدا الكلمة المفتاحية vararg. إذًا، ما هي مهمتها؟

الكلمة المفتاحية vararg:

تمكننا الكلمة vararg، من إنشاء دالة تستقبل عدد غير محدود من القيم Arguments. وهي اختصار لكلمتي variable arguments. وتكون في أبسط صورها:

fun function(vararg variableName: variableType) : ReturnType

فإذا كان نوع بيانات variableType المتغير variableName عدد صحيح Int، ستستقبل الدالة عدد غير محدود من الأعداد الصحيحة Int… وهكذا لكل أنواع البيانات.

هذا يحدث، ﻷن vararg ستنشئ مصفوفة Array بالقيم التي تستقبلها. لذا يمكننا التعامل مع هذه القيم والوصول إليها، تمامًا كما نفعل مع المصفوفات. وسيكون هذا واضحًا أكثر، في الأمثلة في الفقرات أدناه.

قواعد استخدام vararg:

ولكن قبل كتابة شفرة عبر vararg، دعونا نتعرف على أهم قاعدتين عند استخدامها:

  • يمكن أن تحتوي كل دالة على متغير vararg واحد فقط.
  • المتغير الذي يحمل القيمة vararg، يجب أن يكون هو المعامل الأخير بين قوسي الدالة.

إنشاء دالة بمعامل vararg:

فمثلًا، إذا أردنا كتابة دالة تعيد نوع الفاكهة الذي يناسب اليوم في الأسبوع:

تخلينا عن كتابة الأقواس المعقوفة للدالة واستخدمنا علامة الاسناد =، ﻷن كتلة if الشرطية عبارة عن تعبير يعيد نتيجة واحدة حسب الشرط المعطى للكتلة. وﻷن vararg عبارة عن مصفوفة، أمكننا التعامل مع عناصرها باستخدام الفهرس Index. عند استدعاء هذه الدالة، نرسل لها قيمة لمعامل today، ثم مجموعة غير محددة من القيم لمعامل fruits:

كتبنا صراحةً اسم المعامل today عند استدعاء الدالة، وأسندنا له القيمة Monday. وهذا ما يعرف بـ قيم المعاملات المسماة Named Arguments. استخدمنا هذه الطريقة، لتفريق قيمة المعامل الأول today، عن قيم المعامل الثاني fruits. وعند تنفيذ الشفرة، سيتم طباعة Blueberry، ﻷنها القيمة التي ستعيدها دالة ()fruitToEatToday مقابل القيمة Monday.

إرسال مصفوفة Array أو قائمة List لمعامل vararg:

يمكن ارسال مصفوفة كقيمة لمعامل vararg. ولكن قبل ذلك، علينا تفكيك عناصرها باستخدام العامل ( * ) والذي يُعرف بـ Spread Operator:

وستكون نتيجة التنفيذ هي نفسها كالسابق. أما إذا أردنا استخدام قائمة List، فيجب تحويلها أولًا إلى مصفوفة ثم ارسالها:

استخدمنا الدالة ()toTypedArray من مكتبة كوتلن القياسية، لتحويل القائمة إلى مصفوفة قبل إرسالها إلى الدالة.

تعديل برنامج الآلة الحاسبة:

للتدرب على المعلومات التي وردت في هذا الدرس، يمكننا تطبيقها على برنامج الآلة الحاسبة البسيط من درس الاختبار Test:

نلاحظ أن كل الدوال الأربعة تستقبل معاملين فقط. ولكن ماذا إذا أراد المستخدم جمع أو طرح أو قسمة أو ضرب أكثر من رقمين؟ مثل جمع عدد مكوّن من 100 رقم؟ طبعًا من غير المجدي وضع 100 معامل مختلف لدالة الجمع ()add أو غيرها.

لحسن الحظ لن نضطر لذلك ﻷننا سنستخدم معرفتنا الجديدة بـ vararg، لتحسين برنامجنا، ليستطيع إجراء العمليات الحسابية الأربع الأساسية، على أي عدد يريده مستخدم البرنامج:

عدّلنا على الدوال الأربع وجعلناها تستقبل قيم غير محدودة العدد من نوع الأعداد الصحيحة Int. ثم الدوران على عناصر vararg باستخدام الفهرس Index وحلقة التكرار for.

الآن لنجري اختباراتنا الآلية التي كتبناها في درس الاختبارات، مع إضافة أكثر من عددين كقيم للدوال، لنتأكد من أن برنامج الآلة الحاسبة ما زال يعمل ولم تسبب الإضافات الجديدة مشاكل:

وعند الضغط على الزر الأخضر في برنامج IntelliJ، كانت نتيجة الاختبار في تبويب Run:

كل الدوال الأربع نجحت في الاختبار، وهذا يعني أنها ما زالت تؤدي عملها حتى بعد التغيير. مع الفرق، أن هذه المرة تستقبل أعداد غير محدودة من النوع Int.

معامل دالة main:

حتى الآن في هذه الدورة، كنا نستخدم الدالة الرئيسية ()main، بدون معاملات. ولكن يمكننا إضافة معامل من النوع <Array<String لهذه الدالة:

أو حتى معامل vararg من النوع String:

يمكننا تسمية المعامل كما نحب فهو مجرد متغير، ولكن التسمية المشهورة هي args اختصارًا arguments والتي تعني قيم. وهذا ﻷن هذا المعامل يمكنه استقبال قيم عديدة.

إرسال قيم لمعامل دالة main:

بما أن ()main هي الدالة الرئيسية في برنامج كوتلن، سيستدعيها مترجم كوتلن أولًا. لذا لن نستطيع استدعاؤها وإرسال قيم إليها من دالة أخرى، كما نفعل مع باقي الدوال في البرنامج. إذًا، كيف نرسل لها القيم؟

يمكننا استخدام سطر الأوامر، بنفس الطريقة التي قمنا بها بتنفيذ البرنامج في الدرس السابع من هذه الدورة. ولكن هذه المرة سنرسل قيم لمعامل دالة ()main:

الشفرة أعلاه، ستطبع أول كلمتين يتم ادخالهما للبرنامج من سطر الأوامر. ولكن قبل ذلك كما عرفنا من الدرس السابع، علينا بتجميع وترجمة الشفرة عبر إدخال السطر التالي، في تبويب Terminal في برنامج IntelliJ:

kotlinc -include-runtime Main.kt -d hello.jar

  1. هذا هو المسار الكامل للملف الذي توجد به الشفرة المراد تجميعها.
  2. أمر تجميع الشفرة عبر مترجم كوتلن، وتحويلها إلى ملف بصيغة (jar.) قابلة للتنفيذ على حاسوب جافا الافتراضي.

بعد انتهاء التجميع والترجمة، يجب أن نضع أمر تنفيذ لغة الآلة المترجمة عبر سطر جافا:

java -jar hello.jar Hello World

حيث java -jar hello.jar هو أمر التنفيذ الموجه لجافا، و Hello World هي القيم لمعامل الدالة الرئيسية ()main:

هذا الدرس هو جزء من سلسلة تعليم مبادئ البرمجة بلغة كوتلن. لمُتابعة الدروس منذ البداية ومُشاهدة فهرس المحتويات يمكنك الانتقال إلى الدرس الأول من هنا.

هل أعجبك المحتوى وتريد المزيد منه يصل إلى صندوق بريدك الإلكتروني بشكلٍ دوري؟
انضم إلى قائمة من يقدّرون محتوى إكسڤار واشترك بنشرتنا البريدية.