أساسيات برمجة Dart

الأعداد والقيم المنطقية وتحويل الأنواع

35 دقيقة الدرس 4 من 6

الأعداد في Dart

تمتلك Dart ثلاثة أنواع رقمية تشكل تسلسلاً هرمياً: num هو النوع الأب مع int و double كأبنائه. فهم متى تستخدم كل نوع ضروري لكتابة كود Dart صحيح وفعال.

التسلسل الهرمي لأنواع الأعداد

// num هو الأب لكل من int و double
num anyNumber = 42;      // يمكنه حمل int
anyNumber = 3.14;        // يمكنه أيضاً حمل double

int wholeNumber = 42;    // أعداد صحيحة فقط
double decimalNumber = 3.14; // أعداد عشرية فقط

الأعداد الصحيحة (int)

الأعداد الصحيحة تمثل أرقاماً كاملة بدون فاصلة عشرية. على المنصات الأصلية (الهاتف وسطح المكتب) الأعداد الصحيحة في Dart هي قيم 64-بت بإشارة مما يعطي نطاقاً من حوالي -9.2 كوينتيليون إلى 9.2 كوينتيليون.

العمل مع الأعداد الصحيحة

void main() {
  int age = 28;
  int negative = -100;
  int zero = 0;

  // صيغ مختلفة للأعداد الصحيحة
  int decimal = 255;
  int hex = 0xFF;          // 255 بالست عشري
  int binary = 0b11111111; // 255 بالثنائي

  print(decimal == hex);   // true
  print(hex == binary);    // true

  // أعداد كبيرة مع فواصل سفلية للقراءة
  int population = 7_900_000_000;
  int bytes = 1_073_741_824;
  print(population);  // 7900000000
  print(bytes);       // 1073741824
}
نصيحة: استخدم الشرطة السفلية (_) في الأعداد الكبيرة لتحسين القراءة. يتجاهلها Dart تماماً -- 1_000_000 هي نفسها 1000000 بالضبط.

الأعداد العشرية (double)

الأعداد العشرية تمثل أرقام الفاصلة العائمة 64-بت وفق معيار IEEE 754. يمكنها حمل قيم كسرية وأعداد كبيرة جداً وأعداد صغيرة جداً باستخدام الترميز العلمي.

العمل مع الأعداد العشرية

void main() {
  double pi = 3.14159265;
  double price = 29.99;
  double tiny = 0.001;
  double negative = -273.15;

  // الترميز العلمي
  double speed = 3.0e8;     // 300,000,000 (سرعة الضوء م/ث)
  double small = 1.6e-19;   // 0.00000000000000000016

  print(speed);  // 300000000.0
  print(small);  // 1.6e-19

  // عدد صحيح مُسند لـ double يصبح double تلقائياً
  double value = 42;  // يُخزن كـ 42.0
  print(value);        // 42.0
}
تحذير: الحساب بالفاصلة العائمة قد ينتج نتائج غير متوقعة بسبب كيفية تمثيل الحاسوب للأعداد العشرية بالثنائي. مثلاً 0.1 + 0.2 يساوي 0.30000000000000004 وليس 0.3. للحسابات المالية فكر في العمل بالأعداد الصحيحة (القروش بدلاً من الريالات).

خصائص ودوال الأعداد المفيدة

خصائص الأعداد

void main() {
  int number = -42;
  double decimal = 3.7;

  // الخصائص
  print(number.isNegative);   // true
  print(number.isEven);       // true
  print(number.isOdd);        // false
  print(decimal.isFinite);    // true
  print(decimal.isInfinite);  // false
  print(decimal.isNaN);       // false
}

دوال الأعداد

void main() {
  double value = 3.7;

  // التقريب
  print(value.round());       // 4 (أقرب عدد صحيح)
  print(value.floor());       // 3 (تقريب لأسفل)
  print(value.ceil());        // 4 (تقريب لأعلى)
  print(value.truncate());    // 3 (حذف الجزء العشري)

  // القيمة المطلقة
  print((-42).abs());         // 42

  // الحصر في نطاق
  int score = 150;
  print(score.clamp(0, 100)); // 100 (محصور بالحد الأقصى)

  // تنسيق الأعداد العشرية
  double pi = 3.14159265;
  print(pi.toStringAsFixed(2));       // 3.14
  print(pi.toStringAsPrecision(4));   // 3.142
}

العوامل الحسابية

يدعم Dart جميع العوامل الحسابية القياسية:

الحساب الأساسي

void main() {
  int a = 10;
  int b = 3;

  print(a + b);   // 13  (جمع)
  print(a - b);   // 7   (طرح)
  print(a * b);   // 30  (ضرب)
  print(a / b);   // 3.3333... (قسمة -- تُرجع دائماً double)
  print(a ~/ b);  // 3   (قسمة صحيحة -- تقطع)
  print(a % b);   // 1   (باقي القسمة)
}
ملاحظة: عامل القسمة العادي / يُرجع دائماً double في Dart حتى عند قسمة عددين صحيحين. استخدم ~/ (القسمة المقطوعة) عندما تريد نتيجة صحيحة.

مكتبة dart:math

للعمليات الرياضية المتقدمة استورد مكتبة dart:math:

استخدام dart:math

import 'dart:math';

void main() {
  // الثوابت
  print(pi);          // 3.141592653589793
  print(e);           // 2.718281828459045

  // الأس والجذر التربيعي
  print(pow(2, 10));  // 1024
  print(sqrt(144));   // 12.0

  // الأصغر والأكبر
  print(min(5, 10));  // 5
  print(max(5, 10));  // 10

  // أعداد عشوائية
  var random = Random();
  print(random.nextInt(100));    // 0-99
  print(random.nextDouble());   // 0.0-1.0
  print(random.nextBool());     // true أو false
}

القيم المنطقية (bool)

نوع bool له قيمتان فقط: true و false. على عكس JavaScript لا تمتلك Dart قيماً صادقة وكاذبة ضمنية. فقط قيم bool الفعلية يمكن استخدامها في الشروط.

أساسيات القيم المنطقية

void main() {
  bool isActive = true;
  bool isAdmin = false;

  // الاستخدام المباشر في الشروط
  if (isActive) {
    print('المستخدم نشط');
  }

  // Dart لا تملك truthy/falsy مثل JavaScript
  // if (1) { ... }       // خطأ! 1 ليس bool
  // if ('hello') { ... } // خطأ! String ليس bool

  // يجب المقارنة صراحة
  int count = 5;
  if (count > 0) {       // هذا يعمل -- المقارنة تُرجع bool
    print('يحتوي على عناصر');
  }
}
مهم: إذا كنت قادماً من JavaScript تذكر أن Dart صارمة بشأن القيم المنطقية. لا يوجد تحويل ضمني لـ 0 أو "" أو null إلى false. يجب دائماً استخدام تعبيرات منطقية صريحة في الشروط.

العوامل المنطقية

المنطق البولياني

void main() {
  bool a = true;
  bool b = false;

  // AND -- كلاهما يجب أن يكون true
  print(a && b);   // false
  print(a && a);   // true

  // OR -- واحد على الأقل يجب أن يكون true
  print(a || b);   // true
  print(b || b);   // false

  // NOT -- يعكس القيمة
  print(!a);       // false
  print(!b);       // true

  // مثال عملي
  int age = 25;
  bool hasLicense = true;

  bool canDrive = age >= 18 && hasLicense;
  print('يمكنه القيادة: \$canDrive');  // يمكنه القيادة: true
}

عوامل المقارنة

عوامل المقارنة تُرجع قيماً منطقية وتُستخدم بكثرة في الشروط:

جميع عوامل المقارنة

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  (أصغر أو يساوي)
}

تحويل الأنواع

التحويل بين الأنواع مهمة شائعة في Dart. إليك جميع التحويلات المهمة التي تحتاج معرفتها:

بين أنواع الأعداد

تحويل int و double

void main() {
  // int إلى double
  int whole = 42;
  double asDouble = whole.toDouble();
  print(asDouble);       // 42.0

  // double إلى int (يقطع الجزء العشري)
  double decimal = 9.99;
  int asInt = decimal.toInt();
  print(asInt);          // 9 (لا يُقرّب!)

  // double إلى int (مُقرّب)
  int rounded = decimal.round();
  print(rounded);        // 10
}

الأعداد إلى نصوص

عدد إلى نص

void main() {
  int count = 42;
  double price = 9.99;

  // تحويل أساسي
  String countStr = count.toString();
  String priceStr = price.toString();
  print(countStr);  // '42'
  print(priceStr);  // '9.99'

  // تحويل منسق
  print(price.toStringAsFixed(1));  // '10.0'
  print(price.toStringAsFixed(3));  // '9.990'
}

النصوص إلى أعداد

نص إلى عدد (آمن مقابل غير آمن)

void main() {
  // غير آمن -- يطرح FormatException على مدخل غير صالح
  int a = int.parse('42');
  double b = double.parse('3.14');

  // آمن -- يُرجع null على مدخل غير صالح
  int? c = int.tryParse('abc');
  print(c);  // null

  // نمط: tryParse مع قيمة بديلة
  String userInput = 'ليس رقماً';
  int value = int.tryParse(userInput) ?? 0;
  print(value);  // 0 (القيمة البديلة)
}

تحويلات القيم المنطقية

تحويل القيم المنطقية من/إلى أنواع أخرى

void main() {
  // Bool إلى String
  bool active = true;
  String activeStr = active.toString();
  print(activeStr);  // 'true'

  // String إلى Bool (يدوياً)
  String input = 'true';
  bool parsed = input.toLowerCase() == 'true';
  print(parsed);  // true

  // رقم إلى bool
  int status = 1;
  bool isActive = status == 1;
  print(isActive);  // true

  // Bool إلى int
  bool flag = true;
  int flagInt = flag ? 1 : 0;
  print(flagInt);  // 1
}

العوامل المدركة للقيم الفارغة

عند العمل مع تحويلات الأنواع يمكن أن تكون القيم null غالباً. يوفر Dart عوامل مدركة للقيم الفارغة للتعامل مع هذا بأناقة:

العوامل المدركة للقيم الفارغة مع التحويلات

void main() {
  // ?? -- توفير قيمة افتراضية إذا كانت null
  int? parsed = int.tryParse('abc');
  int value = parsed ?? 0;
  print(value);  // 0

  // اختصار في سطر واحد
  int age = int.tryParse('25') ?? 0;
  print(age);  // 25

  int invalid = int.tryParse('مرحبا') ?? -1;
  print(invalid);  // -1
}

مثال عملي: بناء آلة حاسبة

آلة حاسبة مصغرة

import 'dart:math';

void main() {
  double a = 15.0;
  double b = 4.0;

  print('--- الآلة الحاسبة ---');
  print('\$a + \$b = ${a + b}');           // 19.0
  print('\$a - \$b = ${a - b}');           // 11.0
  print('\$a * \$b = ${a * b}');           // 60.0
  print('\$a / \$b = ${(a / b).toStringAsFixed(2)}'); // 3.75
  print('\$a % \$b = ${a % b}');           // 3.0
  print('\$a ^ \$b = ${pow(a, b)}');       // 50625.0
  print('جذر(\$a) = ${sqrt(a).toStringAsFixed(4)}'); // 3.8730
}

تمرين عملي

افتح DartPad وأنشئ برنامجاً: (1) أعلن عن متغيرين صحيحين ومتغيرين عشريين. (2) نفذ جميع العمليات الحسابية (+، -، *، /، ~/، %) واطبع النتائج. (3) استخدم dart:math لحساب الجذر التربيعي والأس لعدد. (4) حوّل سعراً عشرياً إلى عدد صحيح باستخدام round() و floor() و ceil() وقارن النتائج. (5) استخدم tryParse مع عامل ?? لتحويل نص إلى عدد بأمان مع قيمة بديلة.