Dart: أمان القيم الفارغة في Dart
آخر تحديث: 2026-08-26
أمان القيم الفارغة هو درع Dart — المترجم يساعدك على صد 95% من هجمات المؤشر الفارغ.
1. ما ستتعلمه
- مبادئ أمان القيم الفارغة السليم: النوع القابل للفراغ
T?مقابل النوع غير القابل للفراغT - فحوصات الفراغ وترقية النوع
- الكلمة المفتاحية late: التهيئة المؤجلة وضمانات الأمان
- حالات استخدام ومخاطر عامل
! - سيناريو بوب: تصميم أمان القيم الفارغة للتكوينات الاختيارية في خط أنابيب البيانات
2. قصة مطور حقيقي
(1) نقطة الألم: NullPointerException هو أكثر تحطم وقت التشغيل شيوعاً
عانى خط أنابيب البيانات الخاص ببوب من تحطمات وقت التشغيل، 60% منها كانت NullPointerExceptions. API يُرجع معرف طلب فارغ، حقل اختياري مفقود في CSV، خيار تكوين يُستخدم دون ضبطه — كل موقف كان يسبب تحطم البرنامج، مما يؤثر في المتوسط على 50,000 طلب لكل حادثة.
(2) الحل: أمان القيم الفارغة السليم
يقسم أمان القيم الفارغة السليم في Dart 3 الأنواع إلى قابلة للفراغ T? وغير قابلة للفراغ T. يضمن المترجم في وقت الترجمة أن الأنواع غير القابلة للفراغ لا يمكن أن تكون فارغة أبداً.
// غير قابل للفراغ: المترجم يضمن عدم الفراغ
String orderId = 'ORD-001'; // لا يمكن أن يكون فارغاً
// orderId = null; // خطأ ترجمة!
// قابل للفراغ: يجب فحصه قبل الاستخدام
String? nickname; // يمكن أن يكون فارغاً
int length = nickname?.length ?? 0; // وصول آمن
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
(3) الفوائد
- استثناءات المؤشر الفارغ تنتقل من وقت التشغيل إلى وقت الترجمة، مما يقلل الأخطاء المتعلقة بنسبة 95%
- الأنواع غير القابلة للفراغ تجعل عقود API أوضح: أي الحقول مطلوبة واضح على الفور
- ترقية فحص الفراغ تجعل الكود أكثر إيجازاً، مما يلغي الحاجة إلى تحويلات النوع اليدوية
3. مبادئ أمان القيم الفارغة السليم
(1) نظام الأنواع
flowchart TD
A[إعلان المتغير] --> B{هل يمكن أن يكون فارغاً؟}
B -->|نعم| C["T? نوع قابل للفراغ"]
B -->|لا| D["T نوع غير قابل للفراغ"]
C --> E["يجب الفحص قبل الاستخدام"]
E --> F["if (x != null) ← ترقية إلى T"]
C --> G["?? تقديم قيمة افتراضية"]
C --> H["!. فك قسري - محفوف بالمخاطر"]
D --> I["استخدام مباشر - آمن"]
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: أنواع قابلة للفراغ مقابل غير قابلة للفراغ
void main() {
// أنواع غير قابلة للفراغ - لا يمكن أن تحتوي على فارغ
String name = 'DataPipeline';
int count = 100;
double amount = 1500.0;
// name = null; // خطأ ترجمة!
// count = null; // خطأ ترجمة!
// أنواع قابلة للفراغ - يمكن أن تحتوي على فارغ
String? nickname;
int? maxRetries;
double? discountRate;
print(nickname); // null
print(maxRetries); // null
print(discountRate); // null
// الأنواع القابلة للفراغ تتطلب الفحص قبل الاستخدام
// print(nickname.length); // خطأ ترجمة! قد يكون فارغاً
print(nickname?.length); // null (آمن)
print(nickname?.length ?? 0); // 0 (مع افتراضي)
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
| النوع | يمكن أن يكون فارغاً | الفحص قبل الاستخدام | مثال |
|---|---|---|---|
T |
لا | غير مطلوب | String name = 'Bob' |
T? |
نعم | مطلوب | String? name |
4. فحوصات الفراغ وترقية النوع
(1) ترقية النوع
عندما يؤكد المترجم أن متغيراً قابلاً للفراغ ليس فارغاً، فإنه يرقّيه تلقائياً إلى نوع غير قابل للفراغ.
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: ترقية عبر فحص if
void main() {
String? name = 'Bob';
// قبل الفحص - قابل للفراغ
// print(name.length); // خطأ!
// بعد فحص الفراغ - مرقى إلى غير قابل للفراغ
if (name != null) {
print(name.length); // OK! name مرقى إلى String
print(name.toUpperCase()); // OK!
}
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: طرق متعددة لفحص الفراغ
void main() {
String? city;
// الطريقة 1: فحص if-null
if (city != null) {
print(city.length); // مرقى
}
// الطريقة 2: عامل coalesce الفراغ ??
String safeCity = city ?? 'Unknown';
print(safeCity.length); // آمن دائماً
// الطريقة 3: الوصول مع الوعي بالفراغ ?.
int? length = city?.length;
print(length); // null
// الطريقة 4: تهيئة late
late String resolvedCity;
resolvedCity = city ?? 'Unknown';
print(resolvedCity.length); // آمن
// الطريقة 5: assert في وضع التطوير
assert(city != null, 'City must not be null');
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
| طريقة الفحص | الصيغة | تأثير الترقية | الأمان |
|---|---|---|---|
| if-فارغ | if (x != null) |
ترقية إلى T | الأعلى |
| ?? | x ?? default |
يُرجع T | عالٍ |
| ?. | x?.method() |
يُرجع T? | عالٍ |
| ! | x!.method() |
يُعامل كـ T | منخفض (قد يتحطم) |
5. الكلمة المفتاحية late
(1) التهيئة المؤجلة
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: الاستخدام الأساسي لـ late
class DataPipeline {
// late - ستتم التهيئته لاحقاً، لكن مضمون قبل الاستخدام
late String outputPath;
late final DateTime startTime;
void configure(String path) {
outputPath = path; // التعيين الأول
}
void start() {
startTime = DateTime.now(); // late final - يُعيَّن مرة واحدة
print('Pipeline started at $startTime');
}
}
void main() {
final pipeline = DataPipeline();
pipeline.configure('/tmp/reports');
pipeline.start();
// تهيئة late مع تعبير
late final int maxRecords = _loadConfig();
// maxRecords يُحسب فقط عند الوصول الأول
print('Max records: $maxRecords');
}
int _loadConfig() {
print('Loading config...');
return 1000000;
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: مخاطر late
class RiskyPipeline {
late String config;
void process() {
// إذا لم يُعيَّن config، يُلقي LateInitializationError
print(config); // تحطم محتمل في وقت التشغيل!
}
}
void main() {
final pipeline = RiskyPipeline();
// pipeline.process(); // LateInitializationError!
// النمط الآمن: التهيئة في المُنشئ
final safePipeline = SafePipeline('/etc/config.yaml');
safePipeline.process(); // OK
}
class SafePipeline {
late String config;
SafePipeline(String configPath) {
config = _loadConfig(configPath);
}
void process() => print('Config: $config');
String _loadConfig(String path) => 'Loaded from $path';
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
شكل late |
التهيئة | عدد التعيينات | المخاطرة |
|---|---|---|---|
late T |
قبل الاستخدام | متعدد | متوسطة (تحطم إذا تم الوصول قبل التهيئة) |
late final T |
قبل الاستخدام | 1 | متوسطة |
late final T = expr |
عند الوصول الأول | 1 (تلقائي) | منخفضة |
6. عامل !
(1) فك التغليف القسري
يخبر ! المترجم "أنا متأكد أن هذه القيمة ليست فارغة"، متخطياً فحص الفراغ. ومع ذلك، إذا كانت القيمة فارغة، فسيُلقي TypeError.
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: استخدام !
void main() {
String? name = 'Bob';
// عندما تعرف أن القيمة غير فارغة
print(name!.length); // 3 - OK لأن name هو 'Bob'
// خطير: إذا كان فارغاً، يتحطم!
String? maybeNull;
// print(maybeNull!.length); // TypeError وقت التشغيل!
// بديل آمن: استخدم ?? أو فحص if-null
print(maybeNull?.length ?? 0); // 0 - آمن
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
(2) متى تستخدم !
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: حالات استخدام معقولة لـ !
class Order {
final String id;
final double amount;
Customer? customer; // علاقة اختيارية
Order({required this.id, required this.amount});
// استخدم ! عندما يضمن منطق العمل عدم الفراغ
String get customerName {
// هذا محفوف بالمخاطر - قد يكون customer فارغاً
// return customer!.name; // سيء
// أفضل: وصول آمن مع افتراضي
return customer?.name ?? 'Unknown Customer';
}
}
class Customer {
final String name;
Customer(this.name);
}
void main() {
final order = Order(id: 'ORD-001', amount: 1500.0);
print(order.customerName); // Unknown Customer
// بعد تعيين customer
order.customer = Customer('Alice');
print(order.customerName); // Alice
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
| حالة الاستخدام | موصى به | غير موصى به |
|---|---|---|
| متغيرات قابلة للفراغ | ?. / ?? / if-فارغ |
! |
| قيم إرجاع API | فحص الفراغ | ! |
Collection .first |
.firstOrNull ?? default |
.first! |
| بعد التأكيد | ! (التأكيد يضمن عدم الفراغ) |
— |
7. أمان القيم الفارغة والمجموعات
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: معالجة الفراغ في المجموعات
void main() {
// قائمة بعناصر قابلة للفراغ
List<String?> names = ['Alice', null, 'Bob', null, 'Charlie'];
// تصفية الفراغات - تعمل ترقية النوع
final nonNull = names.whereType<String>().toList();
print(nonNull); // [Alice, Bob, Charlie]
// خريطة بقيم قابلة للفراغ
Map<String, double?> revenue = {
'Electronics': 3600.0,
'Books': null,
'Clothing': 890.0,
};
// تصفية الإدخالات ذات القيم غير الفارغة
final validRevenue = Map.fromEntries(
revenue.entries.where((e) => e.value != null),
);
print(validRevenue); // {Electronics: 3600.0, Clothing: 890.0}
// وصول آمن مع افتراضي
final booksRevenue = revenue['Books'] ?? 0;
print(booksRevenue); // 0
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
8. سيناريو بوب: تصميم أمان القيم الفارغة لخط أنابيب البيانات
▶ مثال
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
: تصميم أمان القيم الفارغة للتكوينات الاختيارية
class PipelineConfig {
// الحقول المطلوبة - غير قابلة للفراغ
final String appName;
final String version;
// الحقول الاختيارية - قابلة للفراغ مع افتراضيات
final String? outputPath;
final String? logLevel;
final double? customTaxRate;
final int? maxRetries;
// محسوبة من اختيارية - غير قابلة للفراغ
String get effectiveOutputPath => outputPath ?? '/tmp/datapipeline/output';
String get effectiveLogLevel => logLevel ?? 'info';
double get effectiveTaxRate => customTaxRate ?? 0.08;
int get effectiveMaxRetries => maxRetries ?? 3;
const PipelineConfig({
required this.appName,
required this.version,
this.outputPath,
this.logLevel,
this.customTaxRate,
this.maxRetries,
});
String get summary => '''
$appName v$version
Output: $effectiveOutputPath
Log: $effectiveLogLevel
Tax: ${(effectiveTaxRate * 100).toStringAsFixed(1)}%
Retries: $effectiveMaxRetries
''';
}
void main() {
// تكوين أدنى - الحقول المطلوبة فقط
final minimal = PipelineConfig(
appName: 'DataPipeline',
version: '1.0.0',
);
print(minimal.summary);
// تكوين كامل
final full = PipelineConfig(
appName: 'DataPipeline',
version: '2.0.0',
outputPath: '/data/reports',
logLevel: 'debug',
customTaxRate: 0.10,
maxRetries: 5,
);
print(full.summary);
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
9. المثال الكامل: معالجة طلبات آمنة الفراغ في خط أنابيب البيانات
// ============================================
// معالجة طلبات آمنة الفراغ لخط أنابيب البيانات
// عرض كامل لأنماط أمان القيم الفارغة
// ============================================
class Customer {
final String name;
final String? email;
final Address? address;
Customer({required this.name, this.email, this.address});
String get displayName => email ?? name;
String get city => address?.city ?? 'Unknown City';
}
class Address {
final String city;
final String? state;
final String country;
Address({required this.city, this.state, required this.country});
String get fullRegion => state != null ? '$city, $state' : city;
}
class Order {
final String id;
final double amount;
final String status;
final Customer? customer;
final String? discountCode;
final double? discountPercent;
Order({
required this.id,
required this.amount,
required this.status,
this.customer,
this.discountCode,
this.discountPercent,
}) : assert(amount > 0, 'Amount must be positive');
double get effectiveDiscount => discountPercent ?? 0;
double get discountedAmount => amount * (1 - effectiveDiscount);
double get tax => discountedAmount * 0.08;
double get total => discountedAmount + tax;
String get customerName => customer?.name ?? 'Guest';
String get customerCity => customer?.city ?? 'Unknown';
String get formattedTotal =>
'\$${total.toStringAsFixed(2)} USD';
@override
String toString() =>
'Order($id, $customerName, ${formattedTotal}, $status)';
}
class OrderProcessor {
final List<Order> _orders = [];
final List<String> _warnings = [];
void addOrder(Order order) {
_orders.add(order);
// فحوصات آمنة الفراغ مع تحذيرات
if (order.customer == null) {
_warnings.add('Order ${order.id}: No customer assigned');
}
if (order.discountCode != null && order.discountPercent == null) {
_warnings.add('Order ${order.id}: Discount code without rate');
}
}
double get totalRevenue =>
_orders.fold(0.0, (sum, o) => sum + o.total);
List<Order> get ordersWithCustomers =>
_orders.where((o) => o.customer != null).toList();
Map<String, double> revenueByCity() {
final result = <String, double>{};
for (final order in _orders) {
final city = order.customerCity;
result.update(city, (v) => v + order.total, ifAbsent: () => order.total);
}
return result;
}
void printReport() {
print('=== DataPipeline Order Report ===');
print('Orders: ${_orders.length}');
print('Revenue: \$${totalRevenue.toStringAsFixed(2)} USD');
print('With customers: ${ordersWithCustomers.length}');
print('\nRevenue by City:');
for (final entry in revenueByCity().entries) {
print(' ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD');
}
if (_warnings.isNotEmpty) {
print('\nWarnings:');
for (final w in _warnings) {
print(' $w');
}
}
}
}
void main() {
final processor = OrderProcessor();
processor.addOrder(Order(
id: 'ORD-001',
amount: 1500.0,
status: 'completed',
customer: Customer(
name: 'Alice',
email: 'alice@example.com',
address: Address(city: 'New York', state: 'NY', country: 'US'),
),
discountPercent: 0.10,
));
processor.addOrder(Order(
id: 'ORD-002',
amount: 3200.0,
status: 'completed',
// لا يوجد عميل - حقل قابل للفراغ
));
processor.addOrder(Order(
id: 'ORD-003',
amount: 890.0,
status: 'pending',
customer: Customer(
name: 'Bob',
address: Address(city: 'London', country: 'UK'),
),
discountCode: 'SAVE20',
// discountPercent فارغ - تحذير!
));
processor.printReport();
}
> **الإخراج:** شغّل في DartPad محلي أو عبر `dart run`. جميع الأمثلة في دورة Dart هذه مبنية على Dart 3.x / Flutter 3.x، وقد تختلف النتائج قليلاً حسب إصدار SDK.
الإخراج:
=== DataPipeline Order Report ===
Orders: 3
Revenue: $5172.36 USD
With customers: 2
Revenue by City:
New York: $1458.00 USD
Unknown: $3456.00 USD
London: $961.20 USD
Warnings:
Order ORD-002: No customer assigned
Order ORD-003: Discount code without rate
❓ أسئلة شائعة
س: ما الفرق بين أمان القيم الفارغة السليم وغير السليم؟ ج: أمان القيم الفارغة السليم يضمن أن الأنواع غير القابلة للفراغ لا يمكن أن تكون فارغة في جميع أنحاء البرنامج (المترجم يقوم بالتحقق الشامل). الوضع غير السليم (مهمل) يسمح لمسارات معينة بتجاوز الفحوصات. Dart 3 يستخدم السليم افتراضياً.
س: متى أستخدم
lateبدلاً من نوع قابل للفراغ؟ ج: استخدمlateعندما تكون متأكداً أن المتغير ستتم تهيئته قبل الاستخدام ولا تريده أن يكون فارغاً. إذا كان المتغير يمكن حقاً أن يكون فارغاً (اختياري دلالياً)، فاستخدمT?.
س: هل يجب تجنب
!تماماً؟ ج: ليس تماماً، لكن استخدمه بحذر. السيناريوهات المعقولة تشمل بعد التأكيدات، في كود الاختبار، أو عندما يضمن منطق العمل صراحة عدم الفراغ. في معظم الحالات،??أو?.أكثر أماناً.
س: هل ترقية فحص الفراغ فعالة داخل الإغلاقات (closures)؟ ج: ليس دائماً. إذا كان المتغير قد يتم تعديله خارج الإغلاق، لا يمكن للمترجم ضمان الترقية. احبسه في متغير
finalمحلي لحل هذا.
س: هل معاملات النوع العامة قابلة للفراغ افتراضياً؟ ج: لا.
Tغير قابل للفراغ افتراضياً، وT?قابل للفراغ. هذا يضمن أمان النوع العام.T?هو في الواقع نوع فائق لـT.
س: كيف أتعامل مع العديد من الحقول القابلة للفراغ في تحليل JSON؟ ج: يُنصح باستخدام
??لتقديم قيم افتراضية، أو استخدام حزمةjson_serializableلتوليد طريقةfromJsonتلقائياً مع قيم افتراضية. تجنب استخدام!في كل مكان.
س: ما الفرق بين
late finalوfinal؟ ج:finalيجب تعيينه عند الإعلان أو في قائمة تهيئة المُنشئ.late finalيمكن تعيينه أولاً في جسم المُنشئ أو في طريقة لاحقة.late finalيؤخر توقيت التعيين.
📖 ملخص
- أمان القيم الفارغة السليم يقسم الأنواع إلى T (غير قابل للفراغ) و T? (قابل للفراغ)، مع ضمانات على مستوى المترجم
- بعد فحص الفراغ، يقوم المترجم تلقائياً بترقية النوع، مما يلغي الحاجة إلى تحويلات النوع اليدوية
lateيتيح التهيئة المؤجلة، لكن الوصول إليها قبل التهيئة يسبب تحطماً؛late final+ تعبير تهيئة هو الأكثر أماناً- فك التغليف القسري بـ
!محفوف بالمخاطر؛ فضّل??أو?.كبدائل - نمط تصميم تكوين خط أنابيب البيانات: الحقول المطلوبة غير قابلة للفراغ، الحقول الاختيارية قابلة للفراغ + getters تقدم قيماً افتراضية
📝 تمارين
- أساسي (صعوبة ⭐): أعلن عن 5 متغيرات (2 غير قابلة للفراغ، 3 قابلة للفراغ). استخدم فحوصات if-فارغ، و
??، و?.للوصول بأمان إلى المتغيرات القابلة للفراغ بثلاث طرق مختلفة، واطبع النتائج. - متوسط (صعوبة ⭐⭐): صمم فئة
Configباستخدامlateلتأخير تهيئة 3 حقول، وعيّنها في طريقةconfigure(). عمداً إلى الوصول إلى الحقول دون استدعاءconfigure()ولاحظLateInitializationError. - تحدي (صعوبة ⭐⭐⭐): نفّذ عميل API آمن الفراغ حيث تُرجع جميع طلبات الشبكة نوع
Result<T?>. تعامل بشكل صحيح مع ثلاث حالات: الخادم يُرجع فارغ، حقل مفقود، عدم تطابق نوع، كل ذلك دون استخدام!.