Elvis Operator هو عامل ثنائي يُرجع المعامل الأيسر إذا لم يكن فارغاً (null)، والمعامل الأيمن في الحالة المعاكسة. يُكتب على الشكل ?: في Kotlin وGroovy وبعض اللغات الأخرى. وفقاً لوثائق لغة Kotlin، 2024، فإن العامل هو جزء من نظام أمان القيم الفارغة في اللغة ويسمح بتقصير البنى الشرطية إلى سطر واحد دون فقدان readability. على عكس تعبير if-else الكامل، يقوم Elvis Operator بحساب الجزء الأيمن فقط عندما يكون الجزء الأيسر فارغاً، مما يعطي ميزة في الأداء عند استخدام تعبيرات افتراضية مكلفة.
النقاط الرئيسية
Elvis Operator هو عامل ثنائي سُمي تيمناً بتسريحة شعر إلفيس بريسلي. الرمز ?: يشبه بصرياً وجه المغني من الجانب: علامة الاستفهام هي العين والسوالف، والنقطتان هما الفم. يأخذ العامل معاملين: إذا كان الأول غير فارغ — يُعاد هو، وإلا يُعاد الثاني. هذا يسمح باستبدال بنية if-else الكاملة بتعبير قصير واحد.
اسم «Elvis Operator» ترسخ في مجتمعي Kotlin وGroovy، ثم انتقل إلى Xtend ولغات JVM الأخرى. في Swift و Dart، البنية المماثلة تسمى nil-coalescing operator، لكنها متطابقة وظيفياً. ساعد الارتباط البصري بإلفيس بريسلي في أن يصبح العامل واحداً من أكثر الرموز شهرة في بناء جملة لغات البرمجة الحديثة.
Elvis Operator هو جزء من نظام null safety الذي يمنع NullPointerException (NPE). وفقاً لدراسة JetBrains لعام 2023، يشكل NPE 28% من جميع الاستثناءات في كود JVM في الإنتاج. استخدام Elvis Operator يلغي تماماً NPE في نقطة التعيين، مما يضمن قيمة افتراضية. بالاشتراك مع عامل الاستدعاء الآمن ?.، يتم إنشاء سلسلة موثوقة دون كتلة if واحدة.
في Kotlin، يُكتب Elvis Operator على الشكل ?: بين تعبيرين. إذا كان التعبير الأيسر غير فارغ — تكون النتيجة مساوية للتعبير الأيسر، وإلا يُحسب التعبير الأيمن. يُحسب التعبير الأيمن بشكل كسول — فقط عندما يكون المعامل الأيسر فارغاً، وهو أمر مهم للأداء عند استخدام عمليات حسابية مكلفة أو استدعاءات API.
val name: String? = getUserName()
val displayName = name ?: "Guest"
fun getLength(str: String?): Int {
return str?.length ?: 0
}
val config: Config? = loadConfig()
val timeout = config?.timeout ?: 30
println("Timeout: $timeout")
// Elvis مع throw للمعلمات الإلزامية
val requiredId = nullableId ?: throw IllegalArgumentException("ID is required")
// Elvis مع return للخروج المبكر
fun process(data: String?): Result {
val safe = data ?: return Result.failure("No data")
return processInternal(safe)
}
الدمج مع let هو نمط شائع في Kotlin، حيث يوفر Elvis Operator قيمة افتراضية، ويقوم let بتنفيذ إجراء على النتيجة غير الفارغة. هذا الأسلوب يحل محل كتل if-else بأكملها بسلسلة استدعاءات واحدة دون فقدان readability. يمكن أيضاً استخدام Elvis Operator مع throw للإنهاء القسري عند فقدان معامل مطلوب — هذه طريقة أصيلة للتحقق من صحة البيانات المدخلة.
نمط شائع في Kotlin هو Elvis + return. إذا كانت القيمة فارغة، تُرجع الدالة فوراً نتيجة أو تطرح استثناءاً. صيغة Elvis مع return غالباً ما تُستخدم في دوال تحويل البيانات: val processed = rawData ?: return defaultValue. هذا أكثر إحكاماً من guard let في Swift ولا يزيد من تداخل الكود.
Elvis Operator أقصر من if-else ولا يتطلب تكرار المتغير. قارن: val x = a ?: b مقابل val x = if (a != null) a else b. مع التعبيرات المعقدة، يصل تقليل الكود إلى 60%، بينما تكون الدلالات متطابقة تماماً — يمكن للمترجم توليد نفس bytecode لكلا الخيارين.
| المعيار | Elvis Operator | if-else |
|---|---|---|
| الطول | سطر واحد، 5–10 أحرف | 3 أسطر، 15–30 حرفاً |
| تكرار التعبير | لا | نعم (a != null) ? a : b |
| الجانب الأيمن الكسول | نعم | نعم (elvis أقصر) |
| الآثار الجانبية | فقط في الجانب الأيمن | في كلا الفرعين |
| الوضوح | عالٍ للحالات البسيطة | أفضل للمنطق المعقد |
Elvis Operator هو الأمثل لتعيين القيم الافتراضية، وتسلسل استدعاءات الدوال مع الوصول الآمن، وتسجيل القيم المفقودة. الأنماط الاصطلاحية في Kotlin توصي به كبديل لـ if-else لفحوصات null البسيطة في التعبيرات. بالاشتراك مع ?.، ينتج سلاسل مضغوطة بدون متغيرات مؤقتة.
يبقى if-else مفضلاً للشروط المتعددة، عندما تحتاج الآثار الجانبية إلى التنفيذ، أو عندما يكون كلا المعاملين كتل كود معقدة مع عدة عمليات. لا يدعم Elvis Operator الكتل المتداخلة — فقط تعبيرات مفردة لكل معامل. إذا كان الجانب الأيمن يستدعي دالة ذات آثار جانبية، فإن readability لـ if-else تكون أعلى.
Groovy يستخدم نفس بناء الجملة ?: تماماً مثل Kotlin، حيث أن كلتا اللغتين تعملان على JVM وتشتركان في فلسفة null-safety. ظهر العامل في Groovy في وقت سابق — فهو موجود في اللغة منذ الإصدار 1.8، الذي صدر في 2011. يدعم Groovy أيضاً تعيين Elvis: x ?= value (التعيين فقط إذا كان x فارغاً).
def name = getUserName()
def display = name ?: "Guest"
def map = ["key": "value"]
def result = map?.get("missing") ?: "default"
println(result)
// تعيين Elvis في Groovy
def config = null
config ?= "defaultConfig"
assert config == "defaultConfig"
في Swift، يُسمى المكافئ nil-coalescing operator ويُكتب على الشكل ??. في Dart يُستخدم نفس بناء الجملة ??. الفرق هو أن Swift و Dart يتطلبان تطابق أنواع المعاملين، بينما يسمح Kotlin بأنواع مختلفة مع التحويل التلقائي إلى نوع فائق مشترك. في TypeScript، ظهر العامل ?? (nullish coalescing) في الإصدار 3.7 ويعمل فقط مع null و undefined، على عكس || الذي يقوم بتصفية جميع القيم falsy. في PHP، ظهر العامل ?? في الإصدار 7.0، في C# — ?? منذ الإصدار 6.0.
الخطأ الأكثر شيوعاً هو الخلط بين Elvis Operator ?: وعامل الاستدعاء الآمن ?. في Kotlin، ?. يستدعي دالة أو خاصية فقط إذا كان الكائن غير فارغ، بينما ?: يُرجع قيمة افتراضية عندما يكون فارغاً. يتم دمجهما بشكل متسلسل، لكن كل منهما يؤدي وظيفته الخاصة. ينشأ الخلط لدى المبتدئين الذين يحاولون استخدام ?: بدون ?. قبله.
الجانب الأيمن من Elvis يُحسب بشكل كسول، لكن إذا كان يحتوي على استدعاء دالة ذات آثار جانبية، فقد يؤدي ذلك إلى سلوك غير متوقع. أحياناً يضع المطورون عمليات حسابية مكلفة أو تسجيلاً في الجانب الأيمن، والتي لا تُنفذ عندما تكون القيمة غير فارغة. من المهم تذكر أن الجانب الأيمن هو تعبير يُحسب فقط عند الحاجة.
عدة Elvis متتالية قد تعقد قراءة الكود. على سبيل المثال، a ?: b ?: c ?: d يُحسب من اليسار إلى اليمين، مُرجعاً أول قيمة غير فارغة. التجميع عبر الأقواس أو استخراج المنطق في دالة منفصلة يحسن readability ويسهل التصحيح. إذا كانت السلسلة أطول من 3 عناصر، يجب استخدام تعبير when أو دالة مساعدة.
يحاول المطورون المبتدئون أحياناً استخدام Elvis Operator للتحقق من القيم المنطقية: val x = flag ?: false. هذا يعمل فقط إذا كان flag يمكن أن يكون فارغاً. للشروط المنطقية بدون null، نحتاج إلى if-else عادي أو عامل ثلاثي — Kotlin لا يحتوي على عامل ثلاثي، لكنه يُستبدل بتعبير if-else: val x = if (flag) a else b.
الأسئلة الشائعة
Elvis Operator يتحقق فقط من القيمة الفارغة، بينما العامل الثلاثي يقبل أي شرط منطقي. Kotlin لا يحتوي على عامل ثلاثي — يتم استبداله بتعبير if-else. Elvis يحل مهمة واحدة محددة: قيمة افتراضية عند وجود null، بينما العامل الثلاثي يغطي جميع التعبيرات الشرطية.
نعم، الجانب الأيمن يمكن أن يكون استدعاء دالة: val x = a ?: calculateDefault(). تُحسب الدالة فقط عندما تكون a فارغة بفضل التقييم الكسول. هذا يسمح باستخدام عمليات حسابية مكلفة أو استدعاءات API أو استعلامات قاعدة بيانات دون فقدان الأداء عند وجود قيمة.
Java لا يحتوي على Elvis Operator مباشر. ابتداءً من Java 8، يمكن استخدام Optional.ofNullable(value).orElse(default). Java 14+ قدمت تعبيرات switch، لكن ?: الكامل غير موجود. Kotlin و Groovy يوفرانه كبنية نحوية مدمجة في اللغة.
النمط النموذجي هو استدعاء آمن ?. متبوع بـ Elvis. مثال: user?.address?.city ?: «Unknown». إذا كان أي عنصر في السلسلة فارغاً — تُعاد القيمة الافتراضية. هذا بديل مضغوط لفحوصات if المتداخلة، مما يقلص الكود بمقدار 3–5 مرات مقارنة بالطريقة التقليدية.
Elvis Operator هو بنية نحوية على مستوى اللغة، بينما orElse هو أسلوب من Optional في Java. Elvis كسول (الجانب الأيمن يُحسب فقط عند null)، بينما orElse يحسب وسيطه دائماً. للخيار الكسول في Java، يوجد orElseGet الذي يقبل Supplier. Elvis أقصر ولا يتطلب إنشاء Optional.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا