العوامل (الحسابية والمقارنة والمنطقية والإسناد)
ما هي العوامل؟
العوامل هي رموز خاصة تُجري عمليات على القيم (تُسمى المعاملات). لقد رأيت بعض العوامل في الدروس السابقة -- الآن سنغطي جميع عوامل Dart في مرجع شامل واحد. فهم العوامل ضروري لأنك ستستخدمها في كل برنامج Dart تكتبه.
العوامل الحسابية
العوامل الحسابية تُجري الحسابات الرياضية. غطينا الأساسيات سابقاً لكن دعنا نرى الصورة الكاملة بما في ذلك عوامل الزيادة والنقصان.
جميع العوامل الحسابية
void main() {
int a = 15;
int b = 4;
print(a + b); // 19 جمع
print(a - b); // 11 طرح
print(a * b); // 60 ضرب
print(a / b); // 3.75 قسمة (دائماً double)
print(a ~/ b); // 3 قسمة صحيحة (تقطع)
print(a % b); // 3 باقي القسمة
print(-a); // -15 نفي أحادي
}
الزيادة والنقصان
يوفر Dart عوامل ++ و -- لزيادة أو إنقاص القيمة بمقدار 1. الموضع مهم -- البادئة مقابل اللاحقة تُنتج سلوكاً مختلفاً عند الاستخدام داخل تعبير.
البادئة مقابل اللاحقة
void main() {
// البادئة: تغير القيمة قبل استخدامها
int a = 5;
int b = ++a; // a تصبح 6 أولاً ثم b تحصل على 6
print('a = \$a, b = \$b'); // a = 6, b = 6
// اللاحقة: تغير القيمة بعد استخدامها
int c = 5;
int d = c++; // d تحصل على 5 أولاً ثم c تصبح 6
print('c = \$c, d = \$d'); // c = 6, d = 5
// نفس الشيء ينطبق على النقصان
int x = 10;
print(--x); // 9 (بادئة: نقصان ثم طباعة)
print(x--); // 9 (لاحقة: طباعة ثم نقصان)
print(x); // 8 (تم النقصان الآن)
}
count++; أو ++count;) تتصرف البادئة واللاحقة بشكل متطابق. الفرق يظهر فقط عندما يكون التعبير جزءاً من عبارة أكبر مثل الإسناد أو استدعاء print.عوامل الإسناد
عوامل الإسناد تخزن قيمة في متغير. الإسناد الأساسي هو = لكن Dart يوفر عوامل إسناد مركبة تجمع عملية مع الإسناد.
الإسناد الأساسي والمركب
void main() {
// الإسناد الأساسي
int score = 100;
// عوامل الإسناد المركبة
score += 10; // score = score + 10 -> 110
print(score);
score -= 20; // score = score - 20 -> 90
print(score);
score *= 2; // score = score * 2 -> 180
print(score);
score ~/= 3; // score = score ~/ 3 -> 60
print(score);
score %= 7; // score = score % 7 -> 4
print(score);
}
الإسناد المدرك للقيم الفارغة (??=)
عامل ??= يُسند قيمة فقط إذا كان المتغير حالياً null. إذا كان لديه قيمة بالفعل يتم تخطي الإسناد.
الإسناد المدرك للقيم الفارغة
void main() {
int? a;
print(a); // null
a ??= 10; // a فارغ فأسند 10
print(a); // 10
a ??= 20; // a ليس فارغاً (هو 10) فتخطى
print(a); // 10 (لم يتغير)
// استخدام عملي: تعيين القيم الافتراضية
String? userName;
userName ??= 'زائر';
print(userName); // زائر
}
عوامل المقارنة (العلائقية)
عوامل المقارنة تقارن قيمتين وتُرجع نتيجة bool. هي أساس كل المنطق الشرطي.
جميع عوامل المقارنة
void main() {
int x = 10;
int y = 20;
print(x == y); // false يساوي
print(x != y); // true لا يساوي
print(x > y); // false أكبر من
print(x < y); // true أصغر من
print(x >= 10); // true أكبر أو يساوي
print(x <= 20); // true أصغر أو يساوي
}
مقارنة الأنواع المختلفة
مقارنة خاصة بالأنواع
void main() {
// النصوص تُقارن بالمحتوى
print('Dart' == 'Dart'); // true
print('Dart' == 'dart'); // false (حساسة للحالة)
// الأعداد: int و double يمكن مقارنتها
print(5 == 5.0); // true
// القوائم تُقارن بالمرجع وليس المحتوى
var list1 = [1, 2, 3];
var list2 = [1, 2, 3];
print(list1 == list2); // false (كائنات مختلفة!)
}
== يفحص مساواة القيمة للأنواع البسيطة (int و double و String و bool) لكن مساواة المرجع للكائنات مثل القوائم والخرائط. قائمتان بنفس المحتويات ليستا متساويتين بـ == إلا إذا كانتا نفس الكائن بالضبط.العوامل المنطقية
العوامل المنطقية تجمع التعبيرات المنطقية. تُستخدم بكثرة في الشروط والحلقات ومنطق التحقق.
AND و OR و NOT المنطقية
void main() {
bool isLoggedIn = true;
bool isAdmin = false;
bool hasPermission = true;
// AND (&&) -- الكل يجب أن يكون true
print(isLoggedIn && isAdmin); // false
print(isLoggedIn && hasPermission); // true
// OR (||) -- واحد على الأقل يجب أن يكون true
print(isAdmin || hasPermission); // true
// NOT (!) -- يعكس القيمة
print(!isAdmin); // true
// دمج عوامل متعددة
bool canEdit = isLoggedIn && (isAdmin || hasPermission);
print('يمكنه التعديل: \$canEdit'); // يمكنه التعديل: true
}
التقييم المختصر
يستخدم Dart التقييم المختصر للعوامل المنطقية. هذا يعني أنه يتوقف عن التقييم بمجرد تحديد النتيجة:
سلوك التقييم المختصر
bool checkFirst() {
print('فحص الأول...');
return false;
}
bool checkSecond() {
print('فحص الثاني...');
return true;
}
void main() {
// AND: إذا كان الأول false الثاني لا يُفحص أبداً
bool resultAnd = checkFirst() && checkSecond();
// المخرجات: "فحص الأول..." فقط
// checkSecond() لا تُستدعى أبداً لأن false && أي شيء = false
}
list != null && list.isNotEmpty آمن لأنه إذا كانت القائمة null الفحص الثاني لا يعمل أبداً ويتجنب خطأ null.العوامل البتية
العوامل البتية تعمل على البتات الفردية لقيم الأعداد الصحيحة. رغم أنها لا تُستخدم يومياً إلا أنها مهمة للكود الحساس للأداء والأعلام والبرمجة منخفضة المستوى.
العمليات البتية
void main() {
int a = 5; // ثنائي: 0101
int b = 3; // ثنائي: 0011
print(a & b); // 1 AND (0001)
print(a | b); // 7 OR (0111)
print(a ^ b); // 6 XOR (0110)
print(~a); // -6 NOT (يعكس كل البتات)
// إزاحة البتات
print(a << 1); // 10 إزاحة يسار (1010) -- ضرب في 2
print(a >> 1); // 2 إزاحة يمين (0010) -- قسمة على 2
}
عوامل اختبار الأنواع
عوامل اختبار الأنواع تفحص أو تحول نوع كائن في وقت التشغيل:
is و is! و as
void main() {
dynamic value = 'مرحبا Dart!';
// is -- يفحص إذا كان الكائن من نوع معين
if (value is String) {
print('إنه نص بطول ${value.length}');
}
// is! -- يفحص إذا كان الكائن ليس من نوع معين
if (value is! int) {
print('إنه ليس عدداً صحيحاً');
}
// as -- تحويل النوع
num number = 42;
int integer = number as int;
print(integer); // 42
}
العوامل الشرطية
العوامل الشرطية توفر اختصاراً لمنطق if-else:
العامل الثلاثي (? :)
العامل الثلاثي
void main() {
int age = 20;
// الشرط ? القيمة_إذا_صح : القيمة_إذا_خطأ
String status = age >= 18 ? 'بالغ' : 'قاصر';
print(status); // بالغ
// يمكن تداخله (لكن حافظ على القراءة)
int score = 85;
String grade = score >= 90 ? 'A'
: score >= 80 ? 'B'
: score >= 70 ? 'C'
: 'F';
print(grade); // B
}
العوامل المدركة للقيم الفارغة
جميع العوامل المدركة للقيم الفارغة
void main() {
// ?? -- دمج القيم الفارغة (توفير بديل لـ null)
String? name;
String displayName = name ?? 'زائر';
print(displayName); // زائر
// ??= -- إسناد مدرك للقيم الفارغة
int? count;
count ??= 0;
print(count); // 0
// ?. -- وصول أعضاء مدرك للقيم الفارغة
String? text;
print(text?.length); // null (بدون خطأ!)
print(text?.toUpperCase()); // null (بدون خطأ!)
text = 'مرحبا';
print(text?.length); // 5
}
عامل التتابع (..)
عامل التتابع يتيح لك إجراء عمليات متعددة على نفس الكائن بدون تكرار اسم المتغير. إنه مفيد جداً لتكوين الكائنات.
عمليات التتابع
void main() {
// بدون تتابع (متكرر)
var buffer1 = StringBuffer();
buffer1.write('مرحبا');
buffer1.write(' ');
buffer1.write('بالعالم!');
print(buffer1);
// مع تتابع (نظيف وسلس)
var buffer2 = StringBuffer()
..write('مرحبا')
..write(' ')
..write('بالعالم!');
print(buffer2);
// عملي: بناء قائمة
var numbers = <int>[]
..add(1)
..add(2)
..add(3)
..addAll([4, 5, 6]);
print(numbers); // [1, 2, 3, 4, 5, 6]
}
عامل الانتشار (...)
عامل الانتشار يوسع مجموعة إلى عناصر فردية. يُستخدم عادة عند بناء القوائم أو دمج المجموعات.
عامل الانتشار
void main() {
var first = [1, 2, 3];
var second = [4, 5, 6];
// دمج القوائم بالانتشار
var combined = [...first, ...second];
print(combined); // [1, 2, 3, 4, 5, 6]
// إضافة عناصر حول الانتشار
var withExtra = [0, ...first, 99];
print(withExtra); // [0, 1, 2, 3, 99]
// انتشار مدرك للقيم الفارغة (...?)
List<int>? maybeNull;
var safe = [1, 2, ...?maybeNull, 3];
print(safe); // [1, 2, 3]
}
أولوية العوامل
عندما تظهر عوامل متعددة في تعبير واحد يتبع Dart ترتيب أولوية صارم. إليك أهم المستويات من الأعلى إلى الأدنى:
مثال على الأولوية
void main() {
// الضرب قبل الجمع
print(2 + 3 * 4); // 14 (ليس 20)
print((2 + 3) * 4); // 20 (الأقواس تتجاوز)
// المقارنة قبل المنطقية
print(5 > 3 && 10 < 20); // true
// تُقيّم كـ: (5 > 3) && (10 < 20) = true && true
// عند الشك استخدم الأقواس!
bool result = (5 + 3) > (2 * 3) && !(false || true);
print(result); // true && false = false
}
تمرين عملي
افتح DartPad وأنشئ برنامجاً: (1) استخدم جميع عوامل الإسناد المركبة (+=، -=، *=، ~/=، %=) على متغير واطبع بعد كل خطوة. (2) وضح البادئة مقابل اللاحقة في الزيادة في عبارتي print منفصلتين تُظهران نتائج مختلفة. (3) استخدم العامل الثلاثي لإسناد درجة حرفية بناءً على درجة رقمية. (4) استخدم عوامل ?? و ??= للتعامل مع القيم القابلة للإلغاء مع قيم افتراضية. (5) استخدم عامل التتابع (..) لبناء قائمة بتسلسل عدة استدعاءات .add() ثم اطبع النتيجة.