دروس سكالا

⚡ ملخص ذكي

يقدم دليل Scala التعليمي لغة برمجة ثابتة النوع، تعتمد على JVM، وتجمع بين البرمجة الكائنية والبرمجة الوظيفية. يغطي الدليل التثبيت، وبنية اللغة، والميزات الأساسية، والأطر التي تجعل Scala مثالية لبناء تطبيقات حديثة متزامنة، وقابلة للتوسع، وموجزة.

  • 🔘 النموذج الهجين: تدمج لغة Scala البرمجة الكائنية والبرمجة الوظيفية على JVM، مما يسمح للمطورين بالجمع بين عدم قابلية التغيير، والوظائف من الدرجة الأولى، والتسلسلات الهرمية التقليدية للفئات.
  • ☑️ بناء الجملة موجزة: يقلل استنتاج الأنواع، والوظائف المجهولة، ومطابقة الأنماط من التعليمات البرمجية المتكررة مقارنةً بـ Java بينما تحافظping الكود معبر وسهل القراءة.
  • ✅ الإعداد باستخدام IntelliJ: قم بتثبيت بيئة التطوير المتكاملة (IDE) الخاصة بالإصدار المجتمعي، وأضف المكون الإضافي Scala، وقم بإنشاء كائن يمتد من App لتشغيل برنامج Hello World الأول.
  • 🧪 المكونات الوظيفية الأساسية: يدعم التقييم الكسول، والتطبيق الجزئي، والدوال ذات الرتبة العليا، وعدم قابلية التغيير من خلال val كتابة كود نظيف وقابل للتنبؤ.
  • 🛠️ التزامن والأطر: ممثلو أكا، المستقبل، اللعب، الرفع، و Spark مما يجعل لغة Scala خيارًا قويًا للأنظمة الموزعة وتطبيقات الويب وهندسة البيانات.

دروس سكالا

ما هو سكالا؟

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

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

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

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

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

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

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

بعد النقر على الرابط، ستظهر لك خياران لتثبيت لغة سكالا. في هذا الدرس التعليمي عن سكالا، سنستخدم الخيار الأول. IntelliJ IDEA، مما يوفر دعمًا ممتازًا للغة سكالا بشكل افتراضي.

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

بمجرد زيارة رابط التنزيل، ستجد إصدارين من بيئة التطوير المتكاملة IntelliJ.

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

صفحة تنزيل إصدار IntelliJ Community Edition

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

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

قم بتنزيل IntelliJ مع JBR

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

معالج تثبيت IntelliJ

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

اختر مجلد التثبيت

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

خانة اختيار JDK أثناء التثبيت

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

خيارات التثبيت الافتراضية

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

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

شاشة الترحيب في IntelliJ

لا يزال عليك إضافة إضافة Scala إلى IntelliJ. انقر على القائمة المنسدلة في قائمة التكوين أسفل يمين الشاشة وحدد خيار الإضافات.

قم بتكوين قائمة الإضافات

سوق إضافات IntelliJ

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

الخطوة 6) قم بتثبيت البرنامج المساعد.
انقر فوق "تثبيت" لبدء تنزيل إضافة Scala.

قم بتثبيت إضافة Scala

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

أعد تشغيل موجه أوامر IntelliJ

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

الخطوة 8) اختر "إنشاء مشروع"، والذي يؤدي إلى صفحة يمكنك من خلالها اختيار لغة المشروع.

أنشئ مشروعًا جديدًا في IntelliJ

الخطوة 9) اختر لغة سكالا عن طريق تحديد خانة الاختيار الخاصة بها، ثم انقر فوق "التالي".

اختر لغة سكالا

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

قم بتسمية المشروع وتحديد موقعه

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

يستغرق تحميل الفهارس بعض الوقت، لذا لا تقلق إذا لم تتمكن من التفاعل مع بيئة التطوير المتكاملة (IDE) أثناء ظهور شريط التقدم في الأسفل. تقوم بيئة التطوير المتكاملة بتحميل الملفات اللازمة لتشغيل لغة سكالا وتوفير ميزة الإكمال التلقائي.

الخطوة 11) انقر فوق علامة تبويب المشروع على يسار بيئة التطوير المتكاملة وقم بتوسيعها لعرض محتويات المشروع.

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

في هذه المرحلة، يكون المشروع فارغًا ويحتوي فقط على مجلد ‎.idea وملف hello-world.iml الذي أنشأه بيئة التطوير المتكاملة (IDE). النقطة المهمة هي مجلد src، الذي يحتوي على شفرة المصدر للمشروع. هنا تُنشئ أول ملف Scala لك.

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

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

اختر اسمًا للملف. في هذا الدرس التعليمي للغة سكالا، استخدم مرحباثم اختر "كائن" من القائمة المنسدلة لنوع محتوى ملف Scala.

اختر نوع الكائن

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

تم إنشاء كائن Singleton

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

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

شغّل السهم في IntelliJ

خيار تشغيل Hello

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

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

مخرجات "Hello World" في وحدة التحكم

لقد قمت الآن بتثبيت Scala بنجاح وتشغيل برنامجك الأول.

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

تُستخدم لغة سكالا على نطاق واسع في العديد من المجالات نظرًا لمرونتها وتوافقها مع بيئة جافا الافتراضية (JVM). ومن حالات الاستخدام الشائعة ما يلي:

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

وظائف مجهولة

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

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

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

var timesTwo = (_:Int) * 2

timesTwo(5)
//10

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

تقييم كسول

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

المتغير الذي يُعرَّف بأنه "كسول" لا يُقيَّم في المكان الذي تم تعريفه فيه، وهو ما يُعرف عادةً بالتقييم الفوري. ولا يُقيَّم إلا عند الإشارة إليه لاحقًا في الكود.

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

lazy val myExpensiveValue = expensiveComputation

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

هذا ليس الاستخدام الوحيد للمتغيرات الكسولة. فهي تساعد أيضاً في التعامل مع التبعيات الدائرية في الكود.

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

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

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

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

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

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

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

دالة من الرتبة العليا

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

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

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

توقيع () => Int يعني ذلك أن الدالة لا تأخذ أي مدخلات وتُخرج قيمة عددية صحيحة (Int). مثال على هذه الدالة هو الدالة التي تُولّد عددًا صحيحًا عشوائيًا.

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

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

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

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

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

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

تأخذ الدالة أعلاه قيمة من نوع عدد صحيح (Int). نوع القيمة المرجعة لها هو دالة مجهولة تأخذ قيمة من نوع عدد صحيح (Int). x ويستخدمها كوسيط لدالة القوة.

الكاري

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

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

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

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

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

var multiplyByFive = multiplyTwoNumbers(5) _

multiplyByFive(4)

//returns 20

نمط مطابقة

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

كما أن مطابقة الأنماط في لغة سكالا توفر بنية أكثر سلاسة من عبارة التبديل.

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

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

تُستخدم الشرطة السفلية لالتقاط الحالات التي لا تتطابق في الكود، مما يعكس سلوك الحالة الافتراضية في عبارة switch.

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 _ => //unknown type, do something else
}

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

تتحقق مطابقة الأنماط مما إذا كان المتغير يطابق كل حالة بالترتيب.

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

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

باستخدام فئات الحالة، يمكنك تفكيك الفئة إلى مثالtracالحقول t داخل الكائن.

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

ثبات

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

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

var changeableVariable = 8

changeableVariable = 10
//the compiler does not complain, and the code compiles successfully

println(changeableVariable)
//10

val myNumber = 7

myNumber = 4

//this will not compile

محاولة تعيين قيمة لـ myNumber بعد إعلانها على أنها val يُظهر خطأً أثناء الترجمة: "إعادة تعيين إلى القيمة".

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

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

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

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

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

إليك فئة تُسمى Rectangle تحتوي على قيمتين ودالتين. يمكنك أيضًا استخدام المعاملات. 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 a rectangle with length $length and breadth $breadth"
}
object RectObject {
  def main(args: Array[String]) {
    val rect = new Rectangle(4, 5)
    println(rect.toString)
    println(rect.getArea)
  }
}

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

وراثة

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

من الممكن الوراثة من فئة واحدة أو من عدة فئات. كما يمكن الوراثة من فئات فرعية لها بدورها فئات أصلية، مما يُنشئ تسلسلاً هرمياً للوراثة.

في مثال سكالا أدناه، الفئة الأساسية هي Circleوالفئة المشتقة هي Sphereللدائرة قيمة تُسمى نصف القطر، وهي قيمة موروثة في فئة الكرة. 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
    }
  }

ABStracالإنتاج

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

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

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"
    }
}

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

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

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

فصل دراسي يبدأ بـ abstract يمكن أن تحتوي الكلمة المفتاحية على كل من abstract وغير مفعلtracطرق t. ومع ذلك، فإن الوراثة المتعددة غير مدعومة في abstracفئات t، لذا يمكنك تمديد فئة واحدة فقطtracالفئة t.

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

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

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.10 وتستخدم بشكل أساسي لإضافة وظائف جديدة إلى الفئات المغلقة الموجودة.

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

في مثال 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)

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

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

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

أطر مهمة في Scala

فيما يلي بعض الأطر المهمة للغة سكالا:

  • بلايستشن هو إطار تطبيق ويب مفتوح المصدر يستخدم هندسة MVCتم إصداره في عام 2007، وهو مرخص الآن بموجب ترخيص أباتشي، وأصبح أحد أكثر أطر العمل شيوعًا على GitHub بحلول عام 2013. شركات مثل LinkedIn، Walmartتستخدم كل من سامسونج وإيرو هذا الإطار.
  • مصعد يُعدّ Lift إطار عمل ويب مجاني آخر مكتوب بلغة Scala، تم إطلاقه عام 2007. يستخدم Foursquare إطار عمل Lift، وهو إطار عمل عالي الأداء وسريع في عملية التطوير.
  • عكا يوفر مجموعة أدوات لبناء تطبيقات تعتمد على الرسائل، تتميز بالتزامن العالي والتوزيع والمرونة، على JVM.
  • القطط هي مكتبة توفرtractions for functional programming.
  • Spark هو محرك تحليلات موحد لمعالجة البيانات واسعة النطاق، ويستخدم على نطاق واسع في عمليات البيانات الضخمة وتعلم الآلة.

دعم التزامن

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

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

  • محلي Java الخيوط.
  • ألياف من مكتبات مثل Vertx.
  • ZIO، مكتبة تحتوي على عناصر أساسية للمساعدة في التعامل مع التزامن والحساب غير المتزامن.
  • ذاكرة المعاملات البرمجية (STM) للمعاملات.
  • المستقبل، وهو جزء لا يتجزأ من لغة سكالا.

Java مقابل سكالا

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

سكالا Java
أكثر إيجازًا واختصارًا. أجزاء أكبر نسبياً من التعليمات البرمجية.
صُممت وطُورت لتكون كائنية التوجه ووظيفية في آن واحد. تدعم مجموعة واسعة من ميزات البرمجة الوظيفية مثل التزامن وعدم قابلية التغيير. طُوِّرت في الأصل كلغة برمجة كائنية التوجه، وبدأت بدعم ميزات البرمجة الوظيفية في الإصدارات الحديثة. ومع ذلك، لا تزال أقل قوة من لغة سكالا في مجال البرمجة الوظيفية.
يستخدم نموذج الممثل لدعم التزامن. يستخدم النموذج التقليدي القائم على مؤشر الترابط للتزامن.
يدعم أطر عمل مثل Play و Lift. يدعم Spring و Grails وغيرها الكثير.
يدعم التقييم الكسول. لا يدعم التقييم الكسول بشكل أصلي.
لا توجد أعضاء ثابتة. يحتوي على أعضاء ثابتة.
يدعم التحميل الزائد للمشغل. لا يدعم التحميل الزائد للمشغل.
تُعد عملية تجميع الشفرة المصدرية بطيئة نسبياً. تجميع الكود المصدري أسرع من لغة سكالا.
تتصرف السمات مثل Java 8 واجهات. Java تحاول 8 واجهات سد الفجوة بين الفئات والواجهات.
قد تكون إعادة الكتابة ضرورية أحيانًا عند ترقية الإصدارات. لا تتطلب إعادة الكتابة عادةً بين الإصدارات.
توفر سلامة النوع موثوقية قوية للبرنامج، ولكنها لا تضمن خلوه من الأخطاء بشكل مطلق. نوع ثابت قويping يساعد في تقليل العديد من عيوب وقت التشغيل.
يحتوي على بعض القيود المتعلقة بالتوافق مع الإصدارات السابقة عبر الإصدارات الرئيسية. توافق قوي طويل الأمد مع الإصدارات السابقة.
Operaيتم التعامل مع التورات على أنها استدعاءات للأساليب. Operaتُعتبر tors صيغة خاصة وليست استدعاءات للأساليب.
يدعم التوريث المتعدد باستخدام السمات. لا يدعم التوريث المتعدد باستخدام الفئات؛ بل يستخدم الواجهات بدلاً من ذلك.
Code مكتوب بشكل مختصر. Code مكتوبة بصيغة أكثر تفصيلاً.
Scala لا يحتوي على الكلمة الأساسية الثابتة. Java يحتوي على الكلمة الأساسية الثابتة.

الأسئلة الشائعة

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

نعم. لا تزال لغة سكالا تدعم الأنظمة واسعة النطاق في الشركات التي تستخدم أكا. SparkوKafka. ولا يزال الطلب قوياً في هندسة البيانات والتكنولوجيا المالية والأنظمة الموزعة حيث يكون أداء JVM والبرمجة الوظيفية ذا قيمة.

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

لغة سكالا تُشغّل أباتشي Sparkتُعدّ Scala المحرك الرائد لمعالجة البيانات واسعة النطاق في مسارات الذكاء الاصطناعي. تدعم مكتبات مثل Breeze وSmile وFigaro الحوسبة العددية والتعلم الآلي والنمذجة الاحتمالية، مما يجعل Scala خيارًا قويًا لعلوم البيانات الإنتاجية.

يُنشئ `val` ربطًا غير قابل للتغيير يتم تقييمه فورًا. بينما يُنشئ `var` ربطًا قابلًا للتغيير يمكن إعادة تعيينه. أما `lazy val` فيؤجل التقييم حتى يتم الوصول إلى القيمة لأول مرة، ثم يخزن النتيجة مؤقتًا للقراءات اللاحقة.

تلخيص هذه التدوينة بـ: