Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

عاملا الـ ? و !

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 25 من 110.

عند العمل مع الأنواع التي تقبل القيمة الفارغة (nullable types)، توفر Dart عاملين أساسيين للوصول إلى القيم بأمان. عامل الوصول المدرك للقيم الفارغة (null-aware access operator) ?. و عامل تأكيد عدم الفراغ (null assertion operator) ! يمنحانك التحكم في كيفية التعامل مع القيم التي قد تكون فارغة.

يقوم العامل ?. بالوصول بأمان إلى الخصائص أو الدوال (methods) في قيمة قابلة لأن تكون فارغة (nullable). إذا كانت القيمة null، فإن التعبير بالكامل يعيد null بدلاً من الانهيار (crashing):

String? name = 'Alice';
print(name?.length);  // 5

name = null;
print(name?.length);  // null (لا يوجد تعطل!)

يخبر عامل التشغيل ! لغة Dart "أنا متأكد من أن هذه القيمة ليست null." حيث يقوم بتحويل نوع قابل للقيمة الخالية (nullable) إلى نوع غير قابل للقيمة الخالية (non-nullable)، ولكنه يطرح خطأ إذا كانت القيمة في الواقع null:

String? maybeName = 'Bob';
String definite = maybeName!;  // حسناً - نحن نؤكد أنها ليست null
print(definite.length);  // 3

String? empty = null;
// String crash = empty!;  // خطأ وقت التشغيل! القيمة كانت null

استخدم ?. عندما تريد التعامل مع القيم الفارغة (null) بسلاسة. استخدم ! فقط عندما تكون متأكداً تماماً من وجود قيمة - ربما بعد التحقق منها باستخدام جملة if أو عندما تعلم أن المنطق يضمن وجود قيمة. إن الإفراط في استخدام ! يلغي الغرض من أمان القيم الفارغة (null safety) ويمكن أن يؤدي إلى توقف البرنامج المفاجئ (runtime crashes).

challenge icon

التحدي

سهل

لنقم ببناء نظام مخزون منتجات يوضح كيفية العمل بأمان مع القيم القابلة للإلغاء (nullable) باستخدام عاملي التشغيل ?. و !.

ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:

  • product.dart: قم بتعريف فئة Product التي تمثل عنصراً في المخزون. بعض المنتجات لديها معلومات كاملة، بينما لا يزال البعض الآخر قيد الفهرسة. يجب أن تحتوي الفئة الخاصة بك على:
    • متغير String name غير قابل للإلغاء - يجب أن يكون لكل منتج اسم
    • متغير double price غير قابل للإلغاء - يجب أن يكون لكل منتج سعر
    • متغير String? description قابل للإلغاء - بعض المنتجات ليس لها وصف بعد
    • متغير String? category قابل للإلغاء - بعض المنتجات لم يتم تصنيفها بعد
    • منشئ (constructor) يأخذ name و price كمعلمات مطلوبة
    • دالة getDescriptionLength() تعيد طول الوصف باستخدام ?.، أو null إذا لم يكن هناك وصف
    • دالة getCategoryUppercase() تعيد التصنيف بأحرف كبيرة باستخدام ! - تفترض هذه الدالة أنه قد تم تعيين التصنيف
    • دالة displayProduct() تطبع معلومات المنتج، وتعرض "No description" عندما يكون الوصف null و "Uncategorized" عندما يكون التصنيف null
  • main.dart: استورد فئة المنتج الخاصة بك واستعرض كلا عاملي التشغيل:
    • أنشئ منتجاً باسم 'Laptop' بسعر 999.99، ثم اضبط وصفه على 'High-performance computing device' وتصنيفه على 'Electronics'
    • أنشئ منتجاً باسم 'Mystery Item' بسعر 49.99 (اترك الوصف والتصنيف كـ null)
    • بالنسبة لـ Laptop: استدعِ displayProduct()، واطبع 'Description length: [length]' باستخدام getDescriptionLength()، واطبع 'Category: [uppercase]' باستخدام getCategoryUppercase()
    • بالنسبة لـ Mystery Item: استدعِ displayProduct() واطبع 'Description length: [length]' باستخدام getDescriptionLength() (سيظهر هذا null)

يجب أن تطبع الدالة displayProduct() بهذا التنسيق:

Product: [name] - $[price]
Description: [description or "No description"]
Category: [category or "Uncategorized"]

المخرجات المتوقعة:

Product: Laptop - $999.99
Description: High-performance computing device
Category: Electronics
Description length: 32
Category: ELECTRONICS
Product: Mystery Item - $49.99
Description: No description
Category: Uncategorized
Description length: null

ورقة مرجعية

يقوم معامل الوصول الآمن للقيم الفارغة (null-aware access operator) ?. بالوصول بأمان إلى الخصائص أو الطرق (methods) في القيم التي تقبل أن تكون فارغة (nullable). إذا كانت القيمة فارغة (null)، فإنه يعيد null بدلاً من إلقاء خطأ:

String? name = 'Alice';
print(name?.length);  // 5

name = null;
print(name?.length);  // null (لا يوجد انهيار!)

يقوم معامل تأكيد عدم الفراغ (null assertion operator) ! بتحويل النوع الذي يقبل الفراغ (nullable) إلى نوع لا يقبل الفراغ (non-nullable). استخدمه فقط عندما تكون متأكداً من أن القيمة ليست فارغة، حيث سيؤدي إلى خطأ وقت التشغيل (runtime error) إذا كانت القيمة فارغة بالفعل:

String? maybeName = 'Bob';
String definite = maybeName!;  // جيد - يؤكد أنها ليست فارغة
print(definite.length);  // 3

String? empty = null;
// String crash = empty!;  // خطأ وقت التشغيل!

استخدم ?. للتعامل السلس مع القيم الفارغة، واستخدم ! فقط عندما تكون متأكداً تماماً من وجود قيمة.

جرّب بنفسك

import 'product.dart';

void main() {
  // TODO: قم بإنشاء منتج باسم 'Laptop' وبسعر 999.99
  // ثم قم بتعيين وصفه إلى 'High-performance computing device'
  // وقم بتعيين فئته إلى 'Electronics'
  
  // TODO: قم بإنشاء منتج باسم 'Mystery Item' وبسعر 49.99
  // اترك الوصف والفئة كـ null
  
  // TODO: بالنسبة لـ Laptop:
  // - استدعِ displayProduct()
  // - اطبع "Description length: [length]" باستخدام getDescriptionLength()
  // - اطبع "Category: [uppercase]" باستخدام getCategoryUppercase()
  
  // TODO: بالنسبة لـ Mystery Item:
  // - استدعِ displayProduct()
  // - اطبع "Description length: [length]" باستخدام getDescriptionLength()
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming