0Pricing
Scala for Backend Engineering & Functional Programming · درس

نمط Type Class

تعدد الأشكال الخاص

نمط Type Class درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ما فئة الأنواع؟

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

نشأ هذا المفهوم في Haskell، ويُستخدم على نطاق واسع في مكتبات Scala مثل Cats.

المشكلة التي يحلها

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

الخطوة 1: تعريف السمة

فئة الأنواع هي trait مُعامل بنوع. يصف Show[A] هنا كيفية عرض أي A على شكل String.

trait Show[A] {
  def show(value: A): String
}

@main def run(): Unit = {
  println("Show trait defined")
}

الخطوة 2: توفير المثيلات

لكل نوع ملموس تريدون دعمه، أنشئوا instance من السمة. وتُسمى هذه مثيلات فئة الأنواع.

trait Show[A] { def show(value: A): String }

object Main {
  val intShow: Show[Int] = (v: Int) => s"Int($v)"
  val strShow: Show[String] = (v: String) => s"Str($v)"

  def main(args: Array[String]): Unit = {
    println(intShow.show(7))
    println(strShow.show("hi"))
  }
}

الخطوة 3: استخدام المثيل

تأخذ الدالة المثيل بوصفه معاملًا. وتعمل الدالة نفسها render مع أي نوع لديه مثيل من Show.

trait Show[A] { def show(value: A): String }

object Main {
  def render[A](value: A, s: Show[A]): String = s.show(value)

  val intShow: Show[Int] = (v: Int) => s"<$v>"

  def main(args: Array[String]): Unit = {
    println(render(99, intShow))
  }
}

جعل المثيل ضمنيًا

يُعد تمرير المثيلات يدويًا أمرًا مرهقًا. ويسمح تحديد المثيل بالصفة implicit وتحديد المعامل بالصفة implicit (أو using في Scala 3) للمصرّف بتوفيره تلقائيًا.

trait Show[A] { def show(value: A): String }

object Main {
  implicit val intShow: Show[Int] = (v: Int) => s"<$v>"

  def render[A](value: A)(implicit s: Show[A]): String = s.show(value)

  def main(args: Array[String]): Unit = {
    println(render(42))
  }
}

التعدد الشكلي الظرفي

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

trait Show[A] { def show(value: A): String }

object Main {
  implicit val intShow: Show[Int] = (v: Int) => s"int:$v"
  implicit val boolShow: Show[Boolean] = (v: Boolean) => s"bool:$v"

  def render[A](value: A)(implicit s: Show[A]): String = s.show(value)

  def main(args: Array[String]): Unit = {
    println(render(5))
    println(render(true))
  }
}

التعامل مع الأنواع المخصصة

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

trait Show[A] { def show(value: A): String }

case class User(name: String, age: Int)

object Main {
  implicit val userShow: Show[User] = (u: User) => s"${u.name} (${u.age})"

  def render[A](value: A)(implicit s: Show[A]): String = s.show(value)

  def main(args: Array[String]): Unit = {
    println(render(User("Ada", 36)))
  }
}

فئات الأنواع مقابل الواجهات

تربط الواجهة السلوك بتعريف النوع، أما فئة الأنواع فتفصل بينهما.

  • يمكنكم إضافة مثيل لفئة أنواع إلى نوع لا تملكونه.
  • يمكنكم امتلاك مثيلات متعددة لسياقات مختلفة.
  • يختار المصرّف السلوك في موضع الاستدعاء.

المكونات الثلاثة

تتكون كل فئة أنواع من ثلاثة أجزاء:

  • السمة (العملية المجردة).
  • المثيلات (التطبيقات الخاصة بكل نوع).
  • الواجهة (الدوال التي تتطلب مثيلًا).

ستستكشفون كل جزء في الدروس التالية.

مثال مصغر متكامل

تجميع النمط في دالة عامة تستخدم مثيلًا ضمنيًا.

trait Show[A] { def show(value: A): String }

object Main {
  implicit val intShow: Show[Int] = (v: Int) => s"#$v"
  implicit val strShow: Show[String] = (v: String) => '"' + v + '"'

  def printAll[A](xs: List[A])(implicit s: Show[A]): Unit =
    xs.foreach(x => println(s.show(x)))

  def main(args: Array[String]): Unit = {
    printAll(List(1, 2, 3))
    printAll(List("a", "b"))
  }
}

تحقق سريع

اختبروا فهمكم لنمط فئات الأنواع.

مراجعة

لقد تعلمتم نمط فئة الأنواع:

  • تصف trait مُعامل بنوع عمليةً معينة.
  • تطبّق المثيلات هذه العملية لكل نوع.
  • تتيح معاملات implicit للمصرّف توفير المثيل.
  • يوفر ذلك تعددًا شكليًا ظرفيًا، ويتيح لكم توسيع أنواع لا تملكونها.

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

هل درس «نمط Type Class» مجاني؟

نعم — نص درس «نمط Type Class» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ماذا ستتعلم في «نمط Type Class»؟

تعدد الأشكال الخاص تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «نمط Type Class»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. نمط Type Class
  2. تعريف Instances
  3. Type Classes الشائعة
  4. اشتقاق Type Class
← العودة إلى Scala for Backend Engineering & Functional Programming