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

المعاملات الضمنية

تمرير السياق

المعاملات الضمنية درس مجاني في 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 دروس في المجموع.

تمرير السياق تلقائيًا

تتيح المعلمات الضمنية للمترجم توفير وسيطة نيابةً عنكم، مأخوذة من القيم المعلّمة بـ implicit في النطاق. وهي مناسبة لتمرير سياق «محيطي» مثل الإعدادات أو قواعد التنسيق.

object Main {
  def greet(name: String)(implicit greeting: String): String =
    s"$greeting, $name!"
  implicit val defaultGreeting: String = "Hello"
  def main(args: Array[String]): Unit = {
    println(greet("Ann"))
  }
}

قائمة المعلمات الضمنية

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

object Main {
  def multiply(x: Int)(implicit factor: Int): Int = x * factor
  implicit val f: Int = 10
  def main(args: Array[String]): Unit = {
    println(multiply(5))
  }
}

توفير القيم الضمنية صراحةً

يمكنكم دائمًا تمرير المعلمة الضمنية صراحةً، لتجاوز القيمة الموجودة في النطاق. وهذا مفيد في الحالات الاستثنائية.

object Main {
  def multiply(x: Int)(implicit factor: Int): Int = x * factor
  implicit val f: Int = 10
  def main(args: Array[String]): Unit = {
    println(multiply(5))
    println(multiply(5)(2))
  }
}

حلّ القيم الضمنية حسب النوع

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

object Main {
  case class Config(env: String)
  def run()(implicit cfg: Config): String = s"running in ${cfg.env}"
  implicit val cfg: Config = Config("prod")
  def main(args: Array[String]): Unit = {
    println(run())
  }
}

استخدام implicitly لاستدعاء قيمة

تجلب المساعدة implicitly[T] القيمة الضمنية من النوع T مباشرةً من النطاق، دون تسمية معلمة.

object Main {
  implicit val name: String = "Scala"
  def main(args: Array[String]): Unit = {
    val n = implicitly[String]
    println(n)
  }
}

اختصار قيد السياق

إن قيد السياق [T: Ordering] هو صياغة مختصرة لمعلمة ضمنية من النوع Ordering[T]. ويشيع استخدامه مع فئات الأنواع.

object Main {
  def max[T: Ordering](a: T, b: T): T = {
    val ord = implicitly[Ordering[T]]
    if (ord.gt(a, b)) a else b
  }
  def main(args: Array[String]): Unit = {
    println(max(3, 7))
    println(max("apple", "pear"))
  }
}

تمرير السياق عبر الاستدعاءات

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

object Main {
  case class User(name: String)
  def log(msg: String)(implicit u: User): Unit =
    println(s"[${u.name}] $msg")
  def doWork()(implicit u: User): Unit = {
    log("started")
    log("finished")
  }
  implicit val current: User = User("admin")
  def main(args: Array[String]): Unit = {
    doWork()
  }
}

مواضع بحث المترجم عن القيم الضمنية

يبحث المترجم عن القيم الضمنية في النطاق المحلي والاستيرادات والكائنات المرافقة للأنواع المعنية. وتُعد الكائنات المرافقة مكانًا منظمًا لتوفير القيم الافتراضية.

object Main {
  case class Currency(symbol: String)
  object Currency {
    implicit val default: Currency = Currency("$")
  }
  def price(amount: Int)(implicit c: Currency): String = s"${c.symbol}$amount"
  def main(args: Array[String]): Unit = {
    println(price(50))
  }
}

أخطاء الغموض

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

object Main {
  def label(x: Int)(implicit unit: String): String = s"$x$unit"
  implicit val unit: String = "px"
  def main(args: Array[String]): Unit = {
    // Only one implicit String in scope -> no ambiguity
    println(label(12))
  }
}

سلوك شبيه بالقيم الافتراضية

توفر المعلمات الضمنية نوعًا من القيم الافتراضية الواعية بالسياق: إذ قد ينتج عن استدعاء الدالة نفسه نتائج مختلفة تبعًا للقيمة الضمنية الموجودة في النطاق.

object Main {
  def format(n: Double)(implicit decimals: Int): String =
    f"$n%.${decimals}f"
  implicit val d: Int = 2
  def main(args: Array[String]): Unit = {
    println(format(3.14159))
    println(format(3.14159)(4))
  }
}

استخدموا القيم الضمنية باعتدال

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

object Main {
  case class Locale(code: String)
  def hello()(implicit loc: Locale): String =
    if (loc.code == "tr") "Merhaba" else "Hello"
  implicit val loc: Locale = Locale("tr")
  def main(args: Array[String]): Unit = {
    println(hello())
  }
}

تحقّق سريع

كيف يقرر المترجم القيمة التي سيوفرها لمعلمة ضمنية؟

مراجعة

لقد تعلّمتم المعلمات الضمنية (وفق أسلوب Scala 2):

  • علّموا قائمة المعلمات بـ implicit ليتم ملؤها تلقائيًا
  • يتم الحل حسب النوع، ويجب أن تكون القيمة فريدة في النطاق
  • تستدعي implicitly[T] قيمةً؛ وقيود السياق [T: TC] صياغة مختصرة
  • يشمل البحث النطاق المحلي والاستيرادات والكائنات المرافقة
  • استخدموها للسياق المشترك، لا لكل شيء

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

هل درس «المعاملات الضمنية» مجاني؟

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

ماذا ستتعلم في «المعاملات الضمنية»؟

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

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

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

كم من الوقت يستغرق درس «المعاملات الضمنية»؟

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

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

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

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

  1. المعاملات الضمنية
  2. given/using في Scala 3
  3. التحويلات الضمنية
  4. دوال الامتداد
← العودة إلى Scala for Backend Engineering & Functional Programming