🔹 Null Safety في Dart مع أمثلة 🚀
في Dart، تم تقديم Null Safety في الإصدار Dart 2.12 لحل مشكلة القيم null
التي تؤدي إلى أخطاء تشغيل (Null Pointer Exceptions
).
يتيح Null Safety للمطورين التأكد من أن المتغيرات لا تحتوي على null
ما لم يُسمح بذلك صراحةً.
🔹 لماذا Null Safety مهم؟
- يساعد في منع الأخطاء الشائعة الناتجة عن
null
. - يقلل من الحاجة إلى التحقق اليدوي من
null
في الكود. - يحسن الأداء لأن Dart يمكنها تحسين إدارة الذاكرة بناءً على معرفة أن المتغيرات لن تكون
null
.
🔹 أنواع المتغيرات في Null Safety
1️⃣ المتغيرات غير القابلة لأن تكون null
(Non-nullable)
🔹 أي متغير يتم تعريفه بدون ?
لا يمكن أن يكون null
.
dartنسختحرير<code>void main() {
int x = 10; // ✅ لا يمكن أن يكون null
// int y; // ❌ خطأ، يجب تهيئته بقيمة
print(x);
}
</code>
Dart✅ التفسير:
- لا يمكنك ترك المتغير بدون قيمة (
null
غير مسموح به بشكل افتراضي).
2️⃣ المتغيرات القابلة لأن تكون null
(Nullable)
🔹 لإعلان متغير يمكن أن يكون null
، استخدم ?
.
dartنسختحرير<code>void main() {
int? y; // ✅ هذا المتغير يمكن أن يكون null
print(y); // Output: null
}
</code>
Dart✅ التفسير:
int? y
تعني أنy
يمكن أن تكونnull
.
🔹 التعامل مع null
بأمان
1️⃣ !
(Null Assertion Operator)
🔹 يُستخدم لإخبار Dart أن هذا المتغير لن يكون null
، ولكن يجب الحذر لأنه إذا كان null
، سيؤدي إلى خطأ.
dartنسختحرير<code>void main() {
int? number;
print(number!); // ❌ خطأ: لأن number تساوي null
}
</code>
Dart❌ هذا يؤدي إلى خطأ (Unhandled exception
)!
✅ الحل: يجب التأكد أن المتغير ليس null
قبل استخدام !
.
dartنسختحريرvoid main() {
int? number = 10;
print(number!); // ✅ يعمل بشكل صحيح لأنه ليس null
}
2️⃣ ?.
(Null-aware Operator)
🔹 تُستخدم عندما لا نريد حدوث خطأ إذا كان المتغير null
.
dartنسختحرير<code>void main() {
String? name;
print(name?.length); // ✅ Output: null
}
</code>
Dart✅ التفسير:
- إذا كانت
name
تساويnull
، فلن تحدث مشكلة، وسيتم إرجاعnull
.
3️⃣ ??
(Null-coalescing Operator)
🔹 تُستخدم لتوفير قيمة افتراضية إذا كان المتغير null
.
dartنسختحرير<code>void main() {
String? username;
print(username ?? "Guest"); // Output: Guest
}
</code>
Dart✅ التفسير:
- إذا كان
username
null
، سيتم استخدام"Guest"
بدلًا منه.
4️⃣ ??=
(Null-aware Assignment)
🔹 تُستخدم لتعيين قيمة للمتغير فقط إذا كان null
.
dartنسختحرير<code>void main() {
int? value;
value ??= 5;
print(value); // Output: 5
}
</code>
Dart✅ التفسير:
- إذا كان
value
null
، سيتم تعيين5
له.
🔹 Null Safety في List
و Map
1️⃣ List
تحتوي على null
dartنسختحرير<code>void main() {
List<int?> numbers = [1, 2, null, 4];
print(numbers); // Output: [1, 2, null, 4]
}
</code>
Dart✅ التفسير:
List<int?>
تعني أن القائمة يمكن أن تحتوي علىnull
.
2️⃣ List
لا تحتوي على null
dartنسختحرير<code>void main() {
List<int> numbers = [1, 2, 3, 4];
print(numbers); // Output: [1, 2, 3, 4]
}
</code>
Dart✅ التفسير:
List<int>
تعني أن القائمة يجب ألا تحتوي علىnull
.
3️⃣ Map
تحتوي على null
dartنسختحرير<code>void main() {
Map<String, int?> ages = {
"Ali": 30,
"Omar": null,
};
print(ages["Omar"] ?? "Age not available"); // Output: Age not available
}
</code>
Dart✅ التفسير:
Map<String, int?>
تعني أن القيم في الـMap
يمكن أن تكونnull
.
🔹 Null Safety مع الدوال
1️⃣ تحديد أن القيم المرجعة غير قابلة لأن تكون null
dartنسختحرير<code>int add(int a, int b) {
return a + b;
}
void main() {
print(add(5, 10)); // Output: 15
}
</code>
Dart✅ التفسير:
int add(int a, int b)
تعني أن الدالة لن تُرجعnull
.
2️⃣ دالة قد تُرجع null
dartنسختحرير<code>int? findEvenNumber(List<int> numbers) {
for (var num in numbers) {
if (num.isEven) return num;
}
return null;
}
void main() {
print(findEvenNumber([1, 3, 5])); // Output: null
print(findEvenNumber([1, 2, 3])); // Output: 2
}
</code>
Dart✅ التفسير:
int?
تعني أن الدالة قد تُرجعnull
.
🔹 Null Safety في late
🔹 late
تسمح بتأجيل تهيئة المتغير، لكنها تضمن عدم كونه null
عند استخدامه.
dartنسختحرير<code>class User {
late String name;
void setName(String newName) {
name = newName;
}
}
void main() {
User user = User();
user.setName("Ali");
print(user.name); // Output: Ali
}
</code>
Dart✅ التفسير:
late
تسمح بتهيئةname
لاحقًا، ولكنها لا تسمح بأن تكونnull
عند استخدامها.
🔹 الفرق بين !
و late
الميزة | ! (Null Assertion) | late |
---|---|---|
متى يُستخدم؟ | عندما نكون متأكدين أن المتغير لن يكون null . | عندما نريد تأجيل التهيئة ولكن نضمن أنه لن يكون null عند الاستخدام. |
هل يمكن أن يسبب خطأ؟ | نعم، إذا كان null سيسبب Exception . | لا يسبب خطأ طالما تم تعيين قيمة قبل الاستخدام. |
🎯 خلاصة Null Safety
✅ استخدم ?
إذا كنت تريد السماح بـ null
✅ استخدم !
فقط إذا كنت متأكدًا أن المتغير لن يكون null
✅ استخدم ??
أو ??=
لتوفير قيم افتراضية
✅ استخدم ?.
إذا كنت تريد تجنب Null Pointer Exception
✅ استخدم late
إذا كنت تريد تأجيل التهيئة ولكن تضمن عدم وجود null
عند الاستخدام