Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

إعادة تعريف hashCode و ==

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 71 من 110.

بشكل افتراضي، يكون أي كائنين في لغة Dart متساويين فقط إذا كانا يمثلان نفس المثيل تماماً في الذاكرة. وهذا يعني أن الكائنين اللذين يمتلكان قيماً متطابقة لا يزالان يُعتبران مختلفين:

class Point {
  int x, y;
  Point(this.x, this.y);
}

void main() {
  var p1 = Point(3, 4);
  var p2 = Point(3, 4);
  print(p1 == p2);  // false - كائنات مختلفة!
}

لمقارنة الكائنات حسب قيمها، تحتاج إلى تجاوز كل من عامل == و hashCode. يجب دائماً تجاوز هذين الاثنين معاً - إذا كان كائنان متساويين، فيجب أن يكون لهما نفس رمز التجزئة (hash code):

class Point {
  final int x, y;
  Point(this.x, this.y);
  
  @override
  bool operator ==(Object other) {
    if (other is! Point) return false;
    return x == other.x && y == other.y;
  }
  
  @override
  int get hashCode => Object.hash(x, y);
}

void main() {
  var p1 = Point(3, 4);
  var p2 = Point(3, 4);
  print(p1 == p2);  // true - نفس القيم!
}

يُعد hashCode أمراً بالغ الأهمية لمجموعات مثل مفاتيح Set و Map. تقوم الأداة المساعدة Object.hash() في Dart بدمج قيم متعددة في رمز تجزئة (hash code) واحد. وبدون hashCode صحيح، لن تعمل كائناتك بشكل صحيح في المجموعات القائمة على التجزئة حتى لو تم تجاوز ==.

challenge icon

التحدي

سهل

دعنا نبني نظام إحداثيات حيث يمكن مقارنة النقاط بقيمها بدلاً من عناوين ذاكرتها! ستقوم بإنشاء فئة Coordinate تنفذ المساواة القائمة على القيمة بشكل صحيح، مما يجعلها تعمل بشكل صحيح مع فحوصات المساواة والمجموعات القائمة على التجزئة (hash-based collections) مثل Set.

ستقوم بتنظيم الكود الخاص بك في ملفين:

  • coordinate.dart: أنشئ فئة Coordinate تمثل نقطة في فضاء ثنائي الأبعاد مع حقول final int x و final int y. قم بعمل override لكل من عامل التشغيل == و hashCode بحيث يتم اعتبار إحداثيين لهما نفس قيم x و y متساويين. استخدم Object.hash() لإنشاء رمز التجزئة (hash code) من كلا الحقلين.
  • main.dart: استورد ملف الإحداثيات الخاص بك ووضح كيف تغير المساواة القائمة على القيمة سلوك مقارنة الكائنات:
    • أنشئ كائنين منفصلين من Coordinate، كلاهما بقيمة x: 5 و y: 10
    • اطبع ما إذا كانا متساويين باستخدام ==
    • اطبع ما إذا كانا متطابقين (نفس المثيل) باستخدام identical()
    • أنشئ Set<Coordinate> وأضف كلا الإحداثيين إليها
    • اطبع طول المجموعة (يجب أن يكون 1 لأنهما متساويان!)
    • أنشئ إحداثياً ثالثاً بقيمة x: 3 و y: 7، وأضفه إلى المجموعة
    • اطبع الطول النهائي للمجموعة

يوضح هذا التحدي سبب وجوب عمل override لـ hashCode و == معاً دائماً. تستخدم الـ Set رموز التجزئة لتنظيم العناصر، لذا بدون hashCode مناسب، قد يتم تخزين الكائنات المتساوية كنسخ مكررة!

المخرجات المتوقعة:

true
false
1
2

ورقة مرجعية

بشكل افتراضي، يكون كائنان في Dart متساويين فقط إذا كانا نفس المثيل في الذاكرة، وليس إذا كان لهما نفس القيم:

var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2);  // false - مثيلات مختلفة!

لمقارنة الكائنات حسب قيمها، قم بتجاوز (override) كل من عامل التشغيل == و hashCode. يجب دائمًا تجاوزهما معًا:

class Point {
  final int x, y;
  Point(this.x, this.y);
  
  @override
  bool operator ==(Object other) {
    if (other is! Point) return false;
    return x == other.x && y == other.y;
  }
  
  @override
  int get hashCode => Object.hash(x, y);
}

استخدم Object.hash() لدمج قيم متعددة في رمز تجزئة (hash code) واحد. يعد hashCode أمرًا بالغ الأهمية لمجموعات مثل Set و Map - بدونه، لن تعمل الكائنات المتساوية بشكل صحيح في المجموعات القائمة على التجزئة.

للتحقق مما إذا كان كائنان هما نفس المثيل (وليس مجرد قيم متساوية)، استخدم identical():

print(identical(p1, p2));  // false - مثيلات مختلفة

جرّب بنفسك

import 'coordinate.dart';

void main() {
  // TODO: قم بإنشاء كائنين منفصلين من النوع Coordinate، كلاهما بقيم x: 5 و y: 10

  // TODO: اطبع ما إذا كانا متساويين باستخدام ==

  // TODO: اطبع ما إذا كانا متطابقين (نفس النسخة) باستخدام ()identical

  // TODO: قم بإنشاء Set<Coordinate> وأضف كلا الإحداثيين إليها

  // TODO: اطبع طول المجموعة (يجب أن يكون 1 لأنهما متساويان!)

  // TODO: قم بإنشاء إحداثي ثالث بقيم x: 3 و y: 7، وأضفه إلى المجموعة

  // TODO: اطبع الطول النهائي للمجموعة
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming