Dart: ميزات Dart 3 الجديدة

آخر تحديث: 2026-08-26

الميزات الكبرى الثلاث في Dart 3 — ارتقِ بكودك من "يعمل" إلى "أنيق".

1. ما ستتعلمه


2. قصة مطور حقيقي

(1) نقطة الألم: تسلسل أنواع عميق و if-else مطول

يحتوي خط أنابيب البيانات الخاص ببوب على 3 مصادر بيانات (API/File/Database)، لكل منها تكوينات وطرق اتصال مختلفة. نفذها باستخدام الوراثة، لكن التسلسل كان عميقاً والكود كان مطولاً. عند تحليل استجابات API، كانت هناك حاجة لعدد كبير من فحوصات if-else لرموز الحالة وهياكل الاستجابة، مع كتابة 200 سطر من الكود الشرطي لـ 5 أنواع استجابة فقط.

(2) حل ميزات Dart 3 الجديدة

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

DART
// صنف مختوم: أنواع مصادر بيانات شاملة
sealed class DataSource {}
class ApiSource extends DataSource { final String endpoint; ApiSource(this.endpoint); }
class FileSource extends DataSource { final String path; FileSource(this.path); }

// مطابقة أنماط على صنف مختوم - المترجم يضمن معالجة جميع الحالات
String describe(DataSource source) => switch (source) {
  ApiSource(:final endpoint) => 'API: $endpoint',
  FileSource(:final path) => 'File: $path',
};

// السجلات: إرجاع قيم متعددة
(String, double) parseResponse(String raw) => ('ORD-001', 1500.0);
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

(3) الفوائد


3. السجلات (Records)

(1) أساسيات السجلات

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: إنشاء واستخدام السجلات

DART
void main() {
  // سجل موضعي
  var order = ('ORD-001', 1500.0, 'completed');
  print(order.$1);  // ORD-001
  print(order.$2);  // 1500.0
  print(order.$3);  // completed

  // سجل مسمى (مفضل للقراءة)
  var order2 = (id: 'ORD-002', amount: 3200.0, status: 'pending');
  print(order2.id);      // ORD-002
  print(order2.amount);  // 3200.0
  print(order2.status);  // pending

  // مختلط موضعي ومسمى
  var mixed = ('ORD-003', 890.0, category: 'Electronics');
  print(mixed.$1);       // ORD-003
  print(mixed.category); // Electronics
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: السجلات كقيم إرجاع للدوال

DART
// قيم إرجاع متعددة مع السجلات
({String id, double amount, double tax}) calculateOrder(double amount, double taxRate) {
  return (
    id: 'ORD-${DateTime.now().millisecondsSinceEpoch}',
    amount: amount,
    tax: amount * taxRate,
  );
}

// سجل موضعي للتجميع السريع
(String, double) parseAmount(String input) {
  final parts = input.split(':');
  return (parts[0], double.parse(parts[1]));
}

void main() {
  final order = calculateOrder(1500.0, 0.08);
  print('ID: ${order.id}, Amount: \$${order.amount}, Tax: \$${order.tax}');

  final (label, value) = parseAmount('Revenue:52500.75');
  print('$label: \$$value USD');
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.
ميزة السجل الصيغة الوصف
حقول موضعية .$1, .$2 الوصول حسب الموضع
حقول مسماة .name الوصول حسب الاسم
تعليق النوع (String, int) أو ({String name, int count}) نوع صريح
المساواة مساواة القيمة متساوية إذا كانت قيم الحقول متساوية

4. مطابقة الأنماط

(1) أنواع أنماط المطابقة

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: أنماط المتغيرات والتفكيك

DART
void main() {
  // نمط متغير - استخراج القيم
  var (id, amount, status) = ('ORD-001', 1500.0, 'completed');
  print('ID: $id, Amount: $amount, Status: $status');

  // تفكيك السجل مع الحقول المسماة
  var (:id, :amount, :status) = (id: 'ORD-002', amount: 3200.0, status: 'pending');
  print('ID: $id, Amount: $amount, Status: $status');

  // تفكيك القائمة
  var [first, second, ...rest] = [1, 2, 3, 4, 5];
  print('First: $first, Second: $second, Rest: $rest');

  // تفكيك الخريطة
  var {'id': orderId, 'amount': orderAmount} = {'id': 'ORD-003', 'amount': 890.0};
  print('Order: $orderId, Amount: $orderAmount');
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: نمط if-case

DART
void main() {
  Object value = '1,500.00 USD';

  // مطابقة أنماط if-case
  if (value case String s when s.contains('USD')) {
    print('USD value: $s');
  }

  // مطابقة أنماط على السجل
  var response = (statusCode: 200, body: '{"orders": 1500}');
  if (response case (statusCode: 200, :var body)) {
    print('Success response: $body');
  }

  // مطابقة أنماط على القائمة
  var orders = ['ORD-001', 'ORD-002', 'ORD-003'];
  if (orders case [var first, var second, ...]) {
    print('First two: $first, $second');
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: نمط switch

DART
String classifyOrder(Object value) => switch (value) {
  // نمط النوع
  int i when i > 1000 => 'High value integer: $i',
  int i => 'Low value integer: $i',
  double d when d >= 1000 => 'Premium: \$${d.toStringAsFixed(2)}',
  double d => 'Standard: \$${d.toStringAsFixed(2)}',
  String s => 'String: $s',
  List l when l.length > 100 => 'Large batch: ${l.length} items',
  List l => 'Small batch: ${l.length} items',
  _ => 'Unknown type',
};

// مطابقة أنماط مع السجلات
String describeResponse((int, String) response) => switch (response) {
  (200, var body) => 'OK: $body',
  (404, _) => 'Not Found',
  (500, var msg) => 'Server Error: $msg',
  (>= 400, var msg) => 'Client Error: $msg',
  _ => 'Unknown response',
};

void main() {
  print(classifyOrder(1500));          // High value integer: 1500
  print(classifyOrder(890.0));         // Standard: $890.00
  print(classifyOrder([1, 2, 3]));     // Small batch: 3 items

  print(describeResponse((200, 'OK')));      // OK: OK
  print(describeResponse((404, 'Missing')));  // Not Found
  print(describeResponse((500, 'Crash')));    // Server Error: Crash
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.
نوع النمط الصيغة الاستخدام
نمط متغير var x استخراج القيم
نمط نوع Type x فحص النوع + الاستخراج
نمط ثابت 42, 'hello' مطابقة تامة
نمط علائقي >= 1000 فحص النطاق
نمط منطقي a || b, a && b دمج الشروط
حارس when condition شرط إضافي
بدل _ تجاهل القيمة

5. الفئات المختومة (Sealed Classes)

(1) تسلسل الفئة المختومة

100%
classDiagram
  class DataSource {
    <<sealed>>
  }
  class ApiSource {
    +String endpoint
    +Map headers
  }
  class FileSource {
    +String path
    +Encoding encoding
  }
  class DatabaseSource {
    +String connectionString
  }
  DataSource <|-- ApiSource
  DataSource <|-- FileSource
  DataSource <|-- DatabaseSource
  note for DataSource "ضمان switch شامل"
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: تعريف الفئة المختومة والمطابقة الشاملة

DART
sealed class DataSource {
  const DataSource();
}

class ApiSource extends DataSource {
  final String endpoint;
  final Map<String, String> headers;

  const ApiSource(this.endpoint, {this.headers = const {}});
}

class FileSource extends DataSource {
  final String path;

  const FileSource(this.path);
}

class DatabaseSource extends DataSource {
  final String connectionString;

  const DatabaseSource(this.connectionString);
}

// switch شامل - المترجم يفحص جميع الأنواع الفرعية
String describeSource(DataSource source) => switch (source) {
  ApiSource(:final endpoint, :final headers) =>
      'API: $endpoint (${headers.length} headers)',
  FileSource(:final path) =>
      'File: $path',
  DatabaseSource(:final connectionString) =>
      'Database: $connectionString',
};

// إذا أضفت نوعاً فرعياً جديداً ونسيت تحديث switch،
// سيبلغ المترجم عن خطأ!
void main() {
  final sources = <DataSource>[
    ApiSource('https://api.example.com/orders', headers: {'Authorization': 'Bearer token'}),
    FileSource('/data/orders.csv'),
    DatabaseSource('postgresql://localhost:5432/orders'),
  ];

  for (final source in sources) {
    print(describeSource(source));
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.
ميزة الفئة المختومة الوصف
تقييد الفئة الفرعية يجب تعريفها في نفس المكتبة
فحص الشمولية يجب أن يغطي switch جميع الأنواع الفرعية
ضمان وقت الترجمة switch المفقود سيسبب خطأ ترجمة عند إضافة فئة فرعية جديدة
لا يمكن إنشاء مثيل مجردة ضمنياً

6. الثلاثي في العمل

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: مزيج Sealed + Pattern + Records

DART
// صنف مختوم لنتائج API
sealed class ApiResult<T> {
  const ApiResult();
}

class Success<T> extends ApiResult<T> {
  final T data;
  final (int, String) metadata;  // سجل: (statusCode, message)

  const Success(this.data, this.metadata);
}

class ApiError<T> extends ApiResult<T> {
  final String message;
  final int? statusCode;

  const ApiError(this.message, {this.statusCode});
}

class NetworkError<T> extends ApiResult<T> {
  final String reason;

  const NetworkError(this.reason);
}

// مطابقة الأنماط مع التفكيك
String handleResult(ApiResult<List<String>> result) => switch (result) {
  Success(:final data, metadata: (200, final msg)) =>
      'OK ($msg): ${data.length} items loaded',
  Success(:final data, metadata: (final code, _)) =>
      'Loaded with status $code: ${data.length} items',
  ApiError(:final message, statusCode: final code?) =>
      'API Error [$code]: $message',
  ApiError(:final message) =>
      'API Error: $message',
  NetworkError(:final reason) =>
      'Network Error: $reason',
};

void main() {
  final results = <ApiResult<List<String>>>[
    Success(['ORD-001', 'ORD-002'], (200, 'OK')),
    Success(['ORD-003'], (206, 'Partial Content')),
    ApiError('Rate limit exceeded', statusCode: 429),
    ApiError('Unknown error'),
    NetworkError('Connection timeout'),
  ];

  for (final result in results) {
    print(handleResult(result));
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

7. سيناريو بوب: مصادر بيانات خط أنابيب البيانات وتحليل النتائج

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

: تجريد مصدر البيانات الكامل

DART
sealed class DataSource {
  const DataSource();

  String get displayName;
}

class ApiSource extends DataSource {
  final String endpoint;
  final Duration timeout;

  const ApiSource(this.endpoint, {this.timeout = const Duration(seconds: 10)});

  @override
  String get displayName => 'API ($endpoint)';
}

class FileSource extends DataSource {
  final String path;
  final String format;

  const FileSource(this.path, {this.format = 'csv'});

  @override
  String get displayName => 'File ($path, $format)';
}

class DatabaseSource extends DataSource {
  final String connectionString;
  final String query;

  const DatabaseSource(this.connectionString, {this.query = 'SELECT * FROM orders'});

  @override
  String get displayName => 'Database ($connectionString)';
}

// نتيجة المعالجة مع السجلات
typedef ProcessingResult = ({int processed, int skipped, double revenue, Duration time});

ProcessingResult processDataSource(DataSource source) => switch (source) {
  ApiSource(:final endpoint, :final timeout) => (
    processed: 50000,
    skipped: 120,
    revenue: 525000.0,
    time: timeout,
  ),
  FileSource(:final path, :final format) => (
    processed: 100000,
    skipped: 350,
    revenue: 1200000.0,
    time: Duration(seconds: 5),
  ),
  DatabaseSource(:final connectionString, :final query) => (
    processed: 1200000,
    skipped: 800,
    revenue: 15000000.0,
    time: Duration(seconds: 15),
  ),
};

void main() {
  final sources = <DataSource>[
    ApiSource('https://api.example.com/orders'),
    FileSource('/data/orders.csv'),
    DatabaseSource('postgresql://localhost:5432/orders'),
  ];

  print('=== DataPipeline Source Analysis ===');
  for (final source in sources) {
    final (:processed, :skipped, :revenue, :time) = processDataSource(source);
    print('\n${source.displayName}:');
    print('  Processed: ${processed} orders');
    print('  Skipped:   $skipped records');
    print('  Revenue:   \$${revenue.toStringAsFixed(2)} USD');
    print('  Time:      ${time.inSeconds}s');
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

8. المثال الكامل: نظام معالجة استجابة خط أنابيب البيانات

DART
// ============================================
// نظام معالجة استجابة خط أنابيب البيانات
// فئات مختومة + مطابقة أنماط + سجلات
// ============================================

// صنف مختوم لأنواع الاستجابة المختلفة
sealed class ApiResponse {
  const ApiResponse();
}

class SuccessResponse extends ApiResponse {
  final int statusCode;
  final Map<String, dynamic> data;

  const SuccessResponse(this.statusCode, this.data);
}

class ErrorResponse extends ApiResponse {
  final int statusCode;
  final String message;
  final String? details;

  const ErrorResponse(this.statusCode, this.message, {this.details});
}

class TimeoutResponse extends ApiResponse {
  final Duration timeout;
  final String endpoint;

  const TimeoutResponse(this.timeout, this.endpoint);
}

class RedirectResponse extends ApiResponse {
  final String newEndpoint;
  final int statusCode;

  const RedirectResponse(this.newEndpoint, this.statusCode);
}

// نتيجة المعالجة كسجل
typedef Outcome = ({bool success, String message, double? revenue});

// مطابقة أنماط على جميع أنواع الاستجابة - شامل!
Outcome handleResponse(ApiResponse response) => switch (response) {
  SuccessResponse(statusCode: 200, :final data) when data.containsKey('orders') => (
    success: true,
    message: 'Loaded ${data['orders']} orders',
    revenue: (data['revenue'] as num?)?.toDouble(),
  ),
  SuccessResponse(statusCode: 200, :final data) => (
    success: true,
    message: 'OK but no orders field: ${data.keys}',
    revenue: null,
  ),
  SuccessResponse(statusCode: 206, :final data) => (
    success: true,
    message: 'Partial data: ${data.length} fields',
    revenue: null,
  ),
  SuccessResponse(statusCode: final code) => (
    success: true,
    message: 'Unexpected success code: $code',
    revenue: null,
  ),
  ErrorResponse(statusCode: 429, :final message) => (
    success: false,
    message: 'Rate limited: $message',
    revenue: null,
  ),
  ErrorResponse(statusCode: final code, :final message, :final details?) => (
    success: false,
    message: 'Error [$code]: $message - $details',
    revenue: null,
  ),
  ErrorResponse(statusCode: final code, :final message) => (
    success: false,
    message: 'Error [$code]: $message',
    revenue: null,
  ),
  TimeoutResponse(:final timeout, :final endpoint) => (
    success: false,
    message: 'Timeout after ${timeout.inSeconds}s on $endpoint',
    revenue: null,
  ),
  RedirectResponse(:final newEndpoint, :final statusCode) => (
    success: false,
    message: 'Redirect ($statusCode) to $newEndpoint',
    revenue: null,
  ),
};

void main() {
  final responses = <ApiResponse>[
    SuccessResponse(200, {'orders': 50000, 'revenue': 525000.0}),
    SuccessResponse(200, {'products': 3000}),
    SuccessResponse(206, {'partial': true}),
    ErrorResponse(429, 'Rate limit exceeded'),
    ErrorResponse(500, 'Internal server error', details: 'Database connection lost'),
    ErrorResponse(404, 'Not found'),
    TimeoutResponse(const Duration(seconds: 30), '/api/v1/orders'),
    RedirectResponse('/api/v2/orders', 301),
  ];

  print('=== DataPipeline Response Handler ===\n');
  for (final response in responses) {
    final (:success, :message, :revenue) = handleResponse(response);
    final status = success ? 'OK' : 'FAIL';
    final rev = revenue != null ? ' (\$${revenue.toStringAsFixed(2)} USD)' : '';
    print('[$status] $message$rev');
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل في DartPad محلي أو باستخدام `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x؛ قد تختلف النتائج قليلاً حسب إصدار SDK.

الإخراج:

TEXT 📖 للعرض فقط
=== DataPipeline Response Handler ===

[OK] Loaded 50000 orders ($525000.00 USD)
[OK] OK but no orders field: (products)
[OK] Partial data: 1 fields
[FAIL] Rate limited: Rate limit exceeded
[FAIL] Error [500]: Internal server error - Database connection lost
[FAIL] Error [404]: Not found
[FAIL] Timeout after 30s on /api/v1/orders
[FAIL] Redirect (301) to /api/v2/orders

❓ أسئلة شائعة

س: ما الفرق بين السجلات والفئات؟ ج: السجلات هياكل بيانات مجهولة وخفيفة الوزن قائمة على القيمة؛ الفئات لها أسماء، قائمة على المرجع، ويمكن أن يكون لها طرق. السجلات مناسبة لتمرير البيانات البسيطة، بينما الفئات لمنطق الأعمال المعقد.

س: ما الفرق بين الفئة المختومة والفئة المجردة؟ ج: تقيد الفئات المختومة الفئات الفرعية بنفس المكتبة، مما يتيح للمترجم إجراء فحوصات شاملة؛ يمكن أن يكون للفئات المجردة فئات فرعية في أي مكان، مما يمنع الشمولية. استخدم sealed عندما تحتاج إلى ضمانات شاملة.

س: أين يمكن استخدام مطابقة الأنماط؟ ج: تعابير switch، جمل switch، if-case، إعلانات المتغيرات، حلقات for-in. في Dart 3، الأنماط في كل مكان.

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

س: هل يمكن أن يكون للفئة المختومة مُنشئ؟ ج: يمكن أن يكون لها مُنشئات مصنع (تُرجع فئات فرعية)، لكن الفئة نفسها لا يمكن إنشاء مثيل لها (مجردة ضمنياً). المُنشئات مخصصة بشكل أساسي لمشاركة منطق التهيئة بين الفئات الفرعية.

س: هل هناك فرق بين _ و default في تعبير switch؟ ج: وظيفياً، إنهما متطابقان - كلاهما مطابق شامل. يوصي Dart 3 باستخدام _ (نمط البدل) للإيجاز. default هو الصياغة القديمة المحتفظ بها للتوافق.

س: هل يمكن استخدام السجلات كمفاتيح لـ Map؟ ج: نعم. السجلات قائمة على مساواة القيمة وتنفذ تلقائياً == و hashCode. (1, 2) == (1, 2) صحيح.


📖 ملخص


📝 تمارين

  1. أساسي (⭐): عرّف سجلين: سجل موضعي (String, double) يمثل معرف الطلب والمبلغ، وسجل مسمى ({String id, double amount, String status}). أنشئ مثيلات وفكك/اطبعها.
  2. متوسط (⭐⭐): استخدم صنف مختوم لتعريف 3 طرق دفع (CreditCard/PayPal/BankTransfer)، لكل منها حقول مختلفة. نفّذ طريقة describePayment() باستخدام تعبير switch، مع ضمان الشمولية.
  3. تحدي (⭐⭐⭐): صمم نظام معالجة استجابة API كاملاً: استخدم صنف مختوم لتعريف أنواع الاستجابة (Success/ValidationError/ServerError/Timeout)، كل منها يحمل بيانات سجل مختلفة. نفّذ معالج استجابة باستخدام مطابقة الأنماط، مع دمج الأنماط العلائقية وشروط الحارس.

← الدرس السابق | الدرس التالي →

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%