برنامج Scala التعليمي: مثال وكود لغة برمجة Scala

ملخص دروس سكالا

يغطي هذا البرنامج التعليمي Scala جميع جوانب وموضوعات Scala. سوف تتعلم جميع الأساسيات من الصفر مثل ما هو سكالا، عملية تثبيت سكالا، برامج سكالا، وظائف سكالا، التقييم البطيء، واجهة الكتابة، الفئات والكائنات، الميراث، التجريدات، Java واختلافات سكالا، الخ.

ما هو سكالا؟

سكالا هي لغة برمجة ذات نوع ثابت تجمع بين البرمجة الوظيفية والبرمجة الموجهة للكائنات لزيادة قابلية التوسع للتطبيقات. تعمل Scala بشكل أساسي على منصة JVM ويمكن استخدامها أيضًا لكتابة برامج للمنصات الأصلية باستخدام Scala-Native و Javaسيناريو أوقات التشغيل من خلال ScalaJs.

Scala هي لغة قابلة للتطوير تستخدم لكتابة البرامج لمنصات متعددة. ومن هنا حصلت على اسم "سكالا". تهدف هذه اللغة إلى حل مشاكل Java في حين أنها أكثر إيجازًا في نفس الوقت. تم تصميمها في البداية بواسطة مارتن أوديرسكي، وتم إصدارها في عام 2003.

لماذا تعلم سكالا

فيما يلي الأسباب الرئيسية لتعلم لغة برمجة Scala:

  • من السهل تعلم Scala للمبرمجين الموجهين للكائنات، Java المطورين. أصبحت واحدة من اللغات الشعبية في السنوات الأخيرة.
  • تقدم Scala وظائف من الدرجة الأولى للمستخدمين
  • يمكن تنفيذ سكالا على JVMمما يمهد الطريق للتوافق مع اللغات الأخرى.
  • وهو مصمم للتطبيقات المتزامنة والموزعة والمرنة التي تعتمد على الرسائل. إنها واحدة من أكثر اللغات تطلبًا في هذا العقد.
  • إنها لغة موجزة وقوية ويمكن أن تنمو بسرعة وفقًا لطلب مستخدميها.
  • إنه موجه للكائنات ويحتوي على الكثير من ميزات البرمجة الوظيفية التي توفر الكثير من المرونة للمطورين للبرمجة بالطريقة التي يريدونها.
  • تقدم Scala العديد من أنواع البط
  • لديها نموذج أقل إذا كنت قادمًا من Java
  • أطر الرفع والتشغيل المكتوبة في Scala موجودة في منحنى النمو.

كيفية تثبيت سكالا

للبدء في كتابة برامج Scala، تحتاج إلى تثبيته على جهاز الكمبيوتر الخاص بك. للقيام بذلك، سوف تحتاج إلى زيارة موقعهم https://www.scala-lang.org/download/ لتنزيل أحدث إصدار من Scala.

باتباع الرابط، ننتقل إلى خيارين يمكننا اختيارهما لتثبيت Scala على أجهزتنا. بالنسبة لهذا البرنامج التعليمي الخاص بـ Scala، سنقوم بتنزيل IntelliJ IDEA.

كيفية تثبيت سكالا

بمجرد زيارة رابط التنزيل، ستجد نسختين من IntelliJ IDE.

بالنسبة لهذا البرنامج التعليمي الخاص بلغة Scala، سنقوم بتنزيل الإصدار المجتمعي، وهو مجاني ويأتي مع كل ما تحتاجه لكتابة برامج Scala.

كيفية تثبيت سكالا

الخطوة 1) اختر إصدار المجتمع
في الصفحة، انقر على القائمة المنسدلة الخاصة بإصدار المجتمع.

يقدم لنا خيار تنزيل IntelliJ IDE مع JBR الذي يحتوي على تطبيق JDK(Java مجموعة التطوير) OpenJDK الذي يحتاجه Scala لتجميع التعليمات البرمجية وتشغيلها.

كيفية تثبيت سكالا

الخطوة 2) قم بتشغيل التثبيت
بمجرد تنزيل IntelliJ، انقر فوقه نقرًا مزدوجًا لتشغيل معالج التثبيت واتبع الحوار.

كيفية تثبيت سكالا

الخطوة 3) اختر موقع
اختر موقعًا لتثبيت IDE.

كيفية تثبيت سكالا

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

كيفية تثبيت سكالا

الخطوة 4) انقر فوق التالي
اترك الإعدادات الافتراضية الأخرى كما هي وانقر فوق التالي.

كيفية تثبيت سكالا

الخطوة 5) انقر على أيقونة بدء التشغيل
بمجرد اكتمال التثبيت، قم بتشغيل IntelliJ IDE بالنقر فوق رمز بدء التشغيل الخاص به في قائمة بدء التشغيل مثل التطبيق العادي.

كيفية تثبيت سكالا

لا تزال بحاجة إلى اتباع خطوة إضافية تتمثل في إضافة مكون Scala الإضافي إلى IntelliJ؛ يمكنك القيام بذلك عن طريق النقر على القائمة المنسدلة في قائمة التهيئة الموجودة في أسفل يمين الشاشة وتحديد خيار البرنامج الإضافي.

كيفية تثبيت سكالا

كيفية تثبيت سكالا

في علامة التبويب Marketplace، سيؤدي البحث عن Scala إلى عرض المكون الإضافي كنتيجة أولى ضمن علامة اللغات.

الخطوة 6) تثبيت المكوِّن الإضافي
انقر فوق تثبيت، الأمر الذي سيؤدي إلى بدء البرنامج المساعد في التنزيل.

كيفية تثبيت سكالا

الخطوة 7) أعد تشغيل IDE
بعد اكتمال التنزيل، ستتم مطالبتك بإعادة تشغيل IDE حتى يتمكن البرنامج الإضافي المثبت من بدء العمل.

كيفية تثبيت سكالا

بعد إعادة التشغيل، ستجد نفسك في نفس الصفحة التي كانت عليها من قبل عندما قمنا بتشغيل IDE، ولكن هذه المرة قمنا بالفعل بتثبيت البرنامج الإضافي Scala.

برنامج سكالا مرحبا بالعالم

الخطوة 1) حدد خيار إنشاء مشروع، والذي سيقودنا إلى صفحة حيث يمكننا تحديد نوع اللغة التي سيستخدمها مشروعنا.

برنامج سكالا مرحبا بالعالم

الخطوة 2) اختر Scala عن طريق تحديد مربع الاختيار Scala ثم انقر فوق التالي.

برنامج سكالا مرحبا بالعالم

الخطوة 3) حدد موقعًا لحفظ ملف مشاريعنا ومنح مشروعنا اسمًا.

برنامج سكالا مرحبا بالعالم

إذا لم يكن الدليل موجودًا، فسيطالبنا IntelliJ بطلب الإذن لإنشاء المجلد. قبول وانقر فوق "إنهاء". سيتم نقلك إلى مشروع Scala الخاص بك، والذي لا يحتوي حاليًا على أي رمز Scala.

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

الخطوة 4) بعد ذلك، سنضغط على علامة تبويب المشاريع الموجودة على يسار IDE ونقوم بتوسيعها حتى نتمكن من رؤية محتويات مشروعنا.

برنامج سكالا مرحبا بالعالم

في الوقت الحالي، المشروع فارغ ويحتوي فقط على مجلد ‎.idea وملف hello-world.iml الذي تم إنشاؤه بواسطة IDE. نقطة اهتمامنا هي المجلد src. Src هو المكان الذي نقوم فيه بتخزين الكود المصدري لمشروعنا. إنه المكان الذي سنقوم فيه بإنشاء ملف Scala الأول.

الخطوة 5) انقر بزر الماوس الأيمن على src لفتح قائمة لإنشاء ملف Scala جديد.

قم بإنشاء ملف Scala جديد

سنقوم بعد ذلك بإنشاء اسم للملف، وفي برنامج Scala التعليمي هذا سنستخدم hello ثم نختار من القائمة المنسدلة ما سيتم وضعه كمحتوى لملف Scala. حدد "الكائن"

برنامج سكالا مرحبا بالعالم

بمجرد القيام بذلك، سيكون لدينا ملف Scala يحتوي على كائن Singleton الذي سنستخدمه لتشغيل التعليمات البرمجية الخاصة بنا.

برنامج سكالا مرحبا بالعالم

الآن بعد أن أصبح لديك ملف Scala مع كائن Hello. ستكتب برنامجك الأول عن طريق توسيع الكائن الذي قمت بإنشائه باستخدام الكلمة الأساسية App.

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

برنامج سكالا مرحبا بالعالم

برنامج سكالا مرحبا بالعالم

داخل كائن Hello، نكتب دالة واحدة println()‎ تُستخدم لطباعة النص الموجود بداخله إلى وحدة التحكم. سنقوم بتشغيل الكود الخاص بنا بالضغط على السهم الأخضر.

النقر على السهم يعرض لنا خيار تشغيل، مرحبًا، عند النقر عليه، سيبدأ تجميع التعليمات البرمجية الخاصة بنا وبعد بضع ثوانٍ سنرى نتائج برنامجنا مطبوعة من وحدة التحكم المدمجة في IntelliJ IDE.

برنامج سكالا مرحبا بالعالم

وها نحن ذا، لقد نجحنا في تثبيت Scala وتشغيل برنامجنا الأول.

ما يمكنك القيام به مع سكالا

  • تطوير الويب للواجهة الأمامية باستخدام ScalaJS
  • تطوير المحمول، على حد سواء Android التطوير وIOS – مع Scala Native
  • المكتبات من جانب الخادم مثل HTTP4S وAkka-Http وPlay Framework
  • إنترنت الأشياء باستخدام
  • تطوير اللعبة
  • NLP – معالجة اللغات الطبيعية باستخدام مجموعة من مكتبات ScalaNLP
  • اختبار تقنيات البرمجة المتقدمة مثل البرمجة الوظيفية والبرمجة الشيئية
  • قم ببناء تطبيق اتصال متزامن للغاية باستخدام مكتبة JVM المستوحاة من Erlang
  • استخدمه للتعلم الآلي باستخدام مكتبات مثل Figaro التي تقوم بالبرمجة الاحتمالية وApache Spark أن

وظائف مجهولة

لغة سكالا لها وظائف مجهولة، والتي تسمى أيضا حرفيات الوظيفة. كون Scala لغة وظيفية غالبًا ما يعني أن المطورين يقومون بتقسيم المشكلات الكبيرة إلى العديد من المهام الصغيرة وإنشاء العديد من الوظائف لحل هذه المشكلات. لتسهيل إنشاء الوظائف، يحتوي Scala على هذه الوظائف التي يمكن إنشاؤها مثيل بدون اسم. يمكننا تعيينها مباشرة للمتغيرات أو التعريفات "def" كما هو موضح في مثال Scala أدناه:

val multiplyByTwo = (n:Int) => n * 2
def multiplyByThree = (n:Int) => n *3

يمكننا بعد ذلك استخدام الطريقة العادية التي نستخدم بها الوظائف عن طريق تمرير المعلمات إليها فيما يلي.

multiplyByTwo(3)

//6

multiplyByThree(4)

//12

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

لا تقتصر هذه التوابع على الدوال التي تحتوي على وسيطات ويمكن استخدامها لإنشاء مثيل للطرق التي لا تأخذ أي وسيطات.

val sayHello = ()=>{ println("hello") }

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

سبب آخر وراء الإشارة إلى هذه الوظائف أيضًا وظائف مضمنة. يعد استخدام الوظائف المجهولة نمطًا شائعًا يُستخدم على نطاق واسع في مكتبة المجموعات لتنفيذ إجراءات سريعة على المجموعة.

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

val myList = List(1,2,3,4,5,6,7)

val myEvenList = myList.filter((n: Int) => n % 2 == 0)
//List(2,4,6)

val myOddList = myList.filter((n:Int) => n % 2 != 0)
//List(1,3,5,7)

الطرق التي لدينا هنا كوظائف مجهولة هي تلك التي تتحقق مما إذا كانت القيمة التي نحصل عليها من القائمة فردية أو زوجية وتقوم بإرجاع العنصر.

//the one checking that the value is even
(n: Int) => n % 2 == 0

//the one checking that the value is odd
(n:Int) => n % 2 != 0

في Scala، من الممكن أيضًا استخدام أحرف البدل حيث لم يتم تسمية معلمة وظيفتنا المجهولة. على سبيل المثال

var timesTwo = (_:Int)*2

timesTwo(5)
//10

في هذا السيناريو، لا نقوم بتسمية المعلمة التي نمررها. الشيء الوحيد الذي نستخدمه هو الشرطة السفلية لتمثيلها.

تقييم كسول

تقوم معظم اللغات بتقييم المتغيرات ومعلمات الوظائف بشكل تسلسلي، واحدة تلو الأخرى. في Scala، لدينا كلمة رئيسية تسمى Lazy، والتي تساعد في التعامل مع القيم التي لا نريد تقييمها حتى يتم الرجوع إليها.

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

يمكن أن يكون هذا مفيدًا عندما يكون تقييم القيمة عملية حسابية باهظة الثمن، وإذا لم يكن الأمر أن القيمة مطلوبة دائمًا، فيمكننا إنقاذ أنفسنا من تشغيل عملية حسابية باهظة الثمن يمكن أن تبطئ برنامجنا عن طريق جعل المتغير كسولًا.

lazy val myExpensiveValue = expensiveComputation

def runMethod()={
    if(settings == true){
        use(myExpensiveValue)
    }else{
        use(otherValue)
    }
}

هذه ليست حالة الاستخدام الوحيدة للمتغيرات البطيئة. كما أنها تساعد في التعامل مع مشكلات التبعية الدائرية في التعليمات البرمجية.

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

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

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

def sometimesUsedString(someValue:String, defaultValue:=> String)={
 if(someValue != null){
   use(defaultValue)
 }else{
   use(someValue)
   }
 }

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

اكتب الاستدلال

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

var first:String = "Hello, "
var second:String = "World"
var third = first + second
//the compile infers that third is of type String

وظيفة ذات ترتيب أعلى

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

def doMathToInt(n:Int, myMathFunction:Int=>Int): Int ={
    myMathFunction(n)
}

في الدالة المذكورة أعلاه، نقوم بتمرير int والدالة التي تأخذ int وترجع int. يمكننا تمرير أي وظيفة لهذا التوقيع. نعني بالتوقيع مدخلات ومخرجات الوظيفة. توقيع Int=>Int يعني أن الدالة تأخذ Int كمدخل وترجع Int كمخرج لها.

توقيع ()=>Int يعني أن الوظيفة لا تأخذ أي شيء كمدخل لها وترجع Int كمخرج لها. مثال على دالة كهذه هي تلك التي تولد لنا كثافة عشوائية.

def generateRandomInt()={
 return scala.util.Random.nextInt()
}

الوظيفة المذكورة أعلاه لها توقيع ()=>Int

يمكن أن يكون لدينا دالة تحتوي على scala التوقيع ()=>Unit. هذا يعني أن الوظائف لا تأخذ أي شيء ولا تُرجع نوعًا. يمكن أن تقوم الوظيفة بنوع من الحساب عن طريق تغيير شيء ما إلى القيام بشيء محدد مسبقًا.

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

يمكن للدالة ذات الترتيب الأعلى أيضًا إرجاع دالة.

على سبيل المثال، يمكننا إنشاء طريقة من شأنها إنشاء دالة إمداد بالطاقة، أي أخذ رقم وتطبيق القوة عليه.

def powerByFunction(n:Int):Int=>Int = {
  return (x:Int)=> scala.math.pow(x,n).toInt
}

الدالة المذكورة أعلاه تأخذ int. نوع الإرجاع الخاص بنا هو دالة مجهولة تأخذ Int x، * نستخدم int x كوسيطة لوظيفة الطاقة.

الكاري

في Scala، يمكننا تحويل دالة تأخذ وسيطتين إلى دالة تأخذ وسيطة واحدة في كل مرة. عندما نمرر وسيطة واحدة، فإننا نطبقها جزئيًا وينتهي الأمر بوظيفة تتطلب وسيطة واحدة لإكمال الوظيفة. يتيح لنا Currying إنشاء وظائف عن طريق إضافة بعض الوسائط جزئيًا.

يمكن أن يكون هذا مفيدًا لإنشاء الوظائف ديناميكيًا قبل أن يكون لدينا مجموعة كاملة من الوسائط

def multiply two numbers(n:Int)(m:Int): Unit ={
  return n * m
}

إذا أردنا إنشاء دالة تضرب في رقم محدد، فلن نحتاج إلى إنشاء طريقة ضرب أخرى.

يمكننا ببساطة استدعاء .curried في وظيفتنا أعلاه والحصول على دالة تأخذ وسيطة واحدة أولاً وتعيد دالة مطبقة جزئيًا

def multiplyTwoNumbers(n:Int)(m:Int): Unit ={
  return n * m
}

var multiplyByFive = multiplyTwoNumbers(5) 

multiplyByFive(4)

//returns 20

نمط مطابقة

يحتوي Scala على آلية قوية مدمجة لمساعدتنا في التحقق مما إذا كان المتغير يطابق معايير معينة، مثلما نفعل في بيان التبديل في Java أو في سلسلة من عبارات if/else. تحتوي اللغة على مطابقة الأنماط التي يمكننا استخدامها للتحقق مما إذا كان المتغير من نوع معين. تعد مطابقة الأنماط في Scala قوية ويمكن استخدامها لتدمير المكونات التي لها طريقة unapply للحصول على الحقول التي نهتم بها مباشرة من المتغير الذي نطابقه.

توفر مطابقة نمط Scala أيضًا بناء جملة أكثر متعة مقارنة ببيان التبديل.

myItem match {
  case true => //do something
  case false => //do something else
  case  _ => //if none of the above do this by default
}

نحن نقارن المتغير الخاص بنا بمجموعة من الخيارات، وعندما يفي المتغير الذي نطابقه بالمعايير، يتم تقييم التعبير الموجود على الجانب الأيمن من السهم الكبير (=>) ويتم إرجاعه كنتيجة للمطابقة.

نستخدم شرطة سفلية لرصد الحالات التي لا مثيل لها في الكود الخاص بنا. إنه يعكس سلوك الحالة الافتراضية عند التعامل مع عبارات التبديل.

class Animal(var legs:Int,var sound:String)
class Furniture(var legs:Int, var color:Int, var woodType:String)

myItem match {
case myItem:Animal => //do something
case myItem:Furniture => //do something else
case _ => //case we have a type we don't recognize do sth else
}

في الكود أعلاه، يمكنك معرفة نوع متغير myItem واستنادًا إلى هذا التفرع لبعض التعليمات البرمجية المحددة.

تتحقق مطابقة النمط من تطابق المتغير

تعمل الشرطة السفلية كعنصر نائب يطابق أي شرط آخر لا يتطابق مع العناصر الأخرى في بيانات الحالة أعلاه. نأخذ متغير myItem ونستدعي طريقة المطابقة.

  • نتحقق مما إذا كان myItem صحيحًا باستخدام ونقوم ببعض المنطق على الجانب الأيمن من السهم الكبير "=>."
  • نستخدم الشرطة السفلية لمطابقة أي شيء لا يتطابق مع أي من عبارات الحالة التي حددناها في الكود.

باستخدام فئات الحالة، يمكننا أيضًا المضي قدمًا وتدمير الفصل للحصول على حقول داخل الكائن.

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

ثبات

من الممكن إنشاء قيم لا يمكن تغييرها بواسطة وظائف أخرى في Scala باستخدام الكلمة الأساسية val. ويتحقق هذا في Java باستخدام الكلمة الأساسية النهائية. في Scala، نقوم بذلك عن طريق استخدام الكلمة الأساسية val عند إنشاء متغير بدلاً من استخدام var، وهو البديل الذي قد نستخدمه لإنشاء متغير قابل للتغيير.

المتغير المحدد باستخدام الكلمة الأساسية val يكون للقراءة فقط، بينما يمكن قراءة المتغير المحدد بـ var وتغييره بواسطة وظائف أخرى أو بشكل تعسفي بواسطة المستخدم في الكود.

var changeableVariable = 8

changeableVariable =10
//the compiler doesn't complain, and the code compiles successfully

println(changeableVariable)
//10

val myNumber = 7

myNumber = 4

//if we try this the code won't compile

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

لماذا استخدام الثبات؟

تساعدنا الثبات على منع الكود والمبرمجين الآخرين من تغيير قيمنا بشكل غير متوقع، مما قد يؤدي إلى نتائج غير متوقعة إذا كانوا يعتزمون استخدام القيمة التي نخزنها، فيمكنهم بدلاً من ذلك عمل نسخة منها. بهذه الطريقة، يتم منع الأخطاء التي يمكن أن تنتج عن قيام عدة جهات فاعلة بتغيير نفس المتغير.

الفئات والكائنات

نعلم جميعًا أن الكائنات هي كيانات العالم الحقيقي، والطبقة عبارة عن قالب يحدد الكائنات. الطبقات لها كل من الحالة والسلوكيات. الحالات إما قيم أو متغيرات. السلوكيات هي الأساليب في سكالا.

دعونا نلقي نظرة على كيفية تحديد فئة، وإنشاء مثيل لها، واستخدامها باستخدام Scala.

هنا، الفئة تسمى المستطيل، والتي تحتوي على متغيرين ووظيفتين. يمكنك أيضًا استخدام المعلمات l وb مباشرة كحقول في البرنامج. لديك كائن له طريقة رئيسية وقام بإنشاء مثيل للفئة بقيمتين.

على سبيل المثال:

class Rectangle( l: Int,  b: Int) {
  val length: Int = l
  val breadth: Int = b
  def getArea: Int = l * b
  override def toString = s"This is rectangle with length as $length and breadth as  $breadth"
  }
object RectObject {
  def main(args: Array[String]) {
    val rect = new Rectangle(4, 5)
    println(rect.toString)
    println(rect.getArea)    
  }
}

كافة الحقول والطريقة عامة بشكل افتراضي في Scala. من الضروري استخدام التجاوز لأنه تم تعريف طريقة toString للكائن في Scala.

وراثة

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

من الممكن أن ترث من فئة واحدة أو فئات متعددة. من الممكن أيضًا الوراثة من الفئات الفرعية التي لديها نفسها فئاتها الفائقة، مما يؤدي إلى إنشاء تسلسل هرمي للوراثة في هذه العملية.

في مثال Scala أدناه، الفئة الأساسية هي الدائرة، والفئة المشتقة هي المجال. الدائرة لها قيمة تسمى نصف القطر، وهي موروثة في فئة المجال. يتم تجاوز طريقة calcArea باستخدام الكلمة الأساسية override.

على سبيل المثال:

class Circle {
  val radius = 5;
  def calcArea = {
    println(radius * radius )
  }
}
class Sphere extends Circle{
 override def calcArea = {
    println(radius * radius * radius )
  }
}
  object SphereObject{
    def main(args : Array[String]){
      new Sphere().calcArea 
    }
  }

التجريد

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

على سبيل المثال:

trait MakesSound{
    var nameOfSound:String
    def sound():String
}
abstract class HasLegs(var legs:Int){
    val creatureName:String

    def printLegs():String={
        return s"$creatureName has this number of legs: $legs"
    }
}

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

trait DatabaseService{
    def addItemName(itemName:String)
    def removeItem(itemId:Int)
    def updateItem(itemId:Int, newItemName:String)
}

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

يمكن أن يحتوي الفصل الذي يبدأ بكلمة أساسية مجردة على أساليب مجردة وغير مجردة. لكن الميراث المتعدد غير مدعوم في الفصل المجرد. لذلك، يمكنك تمديد فئة مجردة واحدة على الأكثر.

كائنات سينجلتون

Singleton هي فئة يتم إنشاء مثيل لها مرة واحدة فقط في البرنامج. إنه من نمط برمجة شائع ومفيد يُعرف باسم "النمط الفردي". إنه مفيد في إنشاء مثيلات من المفترض أن تكون طويلة العمر وسيتم الوصول إليها بشكل شائع عبر برنامجك الذي تعتبر حالته جزءًا لا يتجزأ من تنسيق أحداث النظام. يعد إنشاء مثل هذه الفئة في Scala أمرًا سهلاً حيث يوفر لنا Scala وسيلة بسيطة لإنشاء مفردات باستخدام الكلمة الأساسية للكائن.

object UserProfile{
    var userName=""
    var isLoggedIn:Boolean = false
}

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

def getLoggedInStatus():Boolean={
   return UserProfile.isLoggedIn
}

def changeLoggedInStatus():Boolean={
    UserProfile.isLoggedIn = !UserProfile.isLoggedIn
    return  UserProfile.isLoggedIn
}

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

الطبقات الضمنية

الفئات الضمنية هي الوظائف الجديدة المضافة بعد الإصدار 2.1. والغرض الأساسي من ذلك هو إضافة وظائف جديدة إلى الفئات المغلقة.

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

في مثال Scala أدناه، تمت إضافة وظيفة جديدة لاستبدال حروف العلة في السلسلة بـ *.

object StringUtil {
  implicit class StringEnhancer(str: String) {
    
    def replaceVowelWithStar: String = str.replaceAll("[aeiou]", "*")
  }
}

تحتاج إلى الاستيراد في الفصل الذي تستخدمه فيه.

import StringUtil.StringEnhancer

object ImplicitEx extends App {
  val msg = "This is Guru99!"
  println(msg.replaceVowelWithStar)
}

البرمجة الشيئية (OOP) مقابل البرمجة الوظيفية (FP)

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

البرمجة الوظيفيةمن ناحية أخرى، يفصل هذا بين البيانات والوظائف التي تعمل على البيانات. وهذا يتيح للمطورين التعامل مع الوظائف باعتبارها التجريد والقوة الدافعة عند نمذجة البرامج.

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

أطر مهمة في Scala

فيما يلي بعض الأطر المهمة لـ Scala

  • بلايستشن هو إطار تطبيق ويب مفتوح المصدر يستخدم هندسة MVC. تم إصداره في عام 2007 وتم ترخيصه الآن ضمن Apache، وأصبح الإطار الأكثر شيوعًا على GitHub في عام 2013. وتستخدم شركات مثل LinkedIn وWalmart وSamsung وEero هذا الإطار.
  • مصعد هو إطار ويب مجاني آخر مكتوب بلغة Scala وتم إطلاقه في عام 2007. يستخدم Foursquare إطار عمل الرفع. إنه عالي الأداء وأسرع في بناء الإطار.
  • عكا
  • القطط
  • Spark

دعم التزامن

  • القيم الموجودة في Scala غير قابلة للتغيير بشكل افتراضي. وهذا يجعلها قابلة للتكيف للغاية مع البيئة المتزامنة.
  • هناك الكثير من الميزات في Scala التي تجعله الأفضل للتطبيقات المتزامنة.
  • تجعل العقود الآجلة والوعود عملية معالجة البيانات بشكل غير متزامن أسهل، وبالتالي دعم التوازي.
  • Akka – مجموعة أدوات تستخدم نموذج التزامن الخاص بالممثل. هناك عدد من الممثلين الذين يتصرفون عندما يتلقون الرسائل.
  • التزامن باستخدام المواضيع من Java يمكن أيضًا دعمه في Scala.
  • تعد معالجة التدفق ميزة رائعة أخرى تتيح المعالجة المستمرة للبيانات في الوقت الفعلي.

تمتلك Scala بعضًا من أفضل مكتبات التزامن في Java النظام البيئي.

  • محلي Java المواضيع
  • ألياف من مكتبات مثل Vertex
  • ZIO – مكتبة تحتوي على عناصر بدائية لمساعدتنا في التعامل مع الحوسبة المتزامنة وغير المتزامنة
  • STM – المعاملة
  • المستقبل - يحمل في ثناياه عوامل لغة سكالا

Java مقابل سكالا

هنا الرئيسي الفرق بين Java وسكالا.

سكالا Java
أكثر إحكاما وإيجازا أجزاء أكبر نسبيًا من التعليمات البرمجية
تم تصميمها وتطويرها لتكون لغة ذات توجه كائني ووظيفي.
يدعم مجموعة واسعة من ميزات البرمجة الوظيفية مثل التزامن والثبات.
تم تطويرها في الأصل كلغة موجهة للكائنات وبدأت في دعم ميزات البرمجة الوظيفية في الأيام الأخيرة. لا تزال غير قوية كلغة برمجة وظيفية.
يستخدم نموذج الممثل لدعم التزامن وهو حديث يستخدم النموذج التقليدي القائم على مؤشر الترابط للتزامن.
يدعم الأطر – اللعب والرفع يدعم الربيع، الكؤوس، وأكثر من ذلك بكثير
يدعم التقييم البطيء لا يدعم التقييم البطيء
لا يوجد أعضاء ثابتة يحتوي على أعضاء ثابتة
يدعم التحميل الزائد للمشغل لا يدعم التحميل الزائد للمشغل
تجميع كود المصدر بطيء نسبيًا تجميع التعليمات البرمجية المصدر أسرع من Scala
السمات - التصرف مثل Java 8 واجهات Java 8 واجهات تحاول سد الفجوة بين الفئات والواجهات
هناك حاجة إلى إعادة الكتابة إعادة الكتابة غير مطلوبة
لا يوجد ضمان بشأن الرموز الخالية من الأخطاء ضمان كامل للعيوب الأقل
يدعم التوافق مع الإصدارات السابقة. Scala لا يدعم التوافق مع الإصدارات السابقة.
Operaيتم التعامل مع Tors بشكل مختلف في Java وليست استدعاءات الأسلوب. يتم التعامل مع جميع العمليات على الإدخالات عبر طريقة يتم استدعاؤها في سكالا.
يدعم الوراثة المتعددة باستخدام الفئات ولكن ليس عن طريق الفئات المجردة لا يدعم الوراثة المتعددة باستخدام الفئات، ولكن عن طريق الواجهات
الكود مكتوب في شكل مضغوط. يتم كتابة التعليمات البرمجية في شكل طويل.
Scala لا يحتوي على الكلمة الأساسية الثابتة. Java يحتوي على الكلمة الأساسية الثابتة.

الملخص

في هذا البرنامج التعليمي، تعلمت كيفية البدء في استخدام Scala. لقد تعلمت أيضًا الميزات الوظيفية والموجهة للكائنات. لقد اكتشفت أيضًا أوجه التشابه والاختلاف بينهما Java وسكالا. من المفترض أن يساعدك هذا البرنامج التعليمي بمجموعة واسعة من الأمثلة الموضحة جيدًا.