דריסת hashCode ו־==
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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. תמיד צריך לדרוס את שניהם יחד — אם שני אובייקטים שווים, חייב להיות להם אותו קוד גיבוב:
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 משלבת כמה ערכים לקוד גיבוב יחיד. ללא hashCode תקין, האובייקטים שלך לא יפעלו כראוי באוספים המבוססים על גיבוב, גם אם == נדרס.
אתגר
קלבואו נבנה מערכת קואורדינטות שבה אפשר להשוות בין נקודות לפי הערכים שלהן ולא לפי כתובות הזיכרון שלהן! תיצרו מחלקת Coordinate שמממשת כראוי שוויון מבוסס ערכים, כך שתפעל נכון בבדיקות שוויון ובאוספים מבוססי גיבוב כמו Set.
תארגנו את הקוד שלכם בשני קבצים:
coordinate.dart: צרו מחלקתCoordinateשמייצגת נקודה במרחב דו־ממדי, עם השדותfinal int xו-final int y. דרסו גם את האופרטור==וגם אתhashCode, כך ששתי קואורדינטות עם אותם ערכים של x ו-y ייחשבו שוות. השתמשו ב-Object.hash()כדי ליצור את קוד הגיבוב משני השדות.main.dart: ייבאו את קובץ הקואורדינטות שלכם והדגימו כיצד שוויון מבוסס ערכים משנה את אופן ההשוואה בין אובייקטים:- צרו שני אובייקטים נפרדים מסוג
Coordinate, שלשניהם x:5ו-y:10 - הדפיסו אם הם שווים באמצעות
== - הדפיסו אם הם זהים (אותו מופע) באמצעות
identical() - צרו
Set<Coordinate>והוסיפו אליו את שתי הקואורדינטות - הדפיסו את אורך הקבוצה (הוא אמור להיות 1, מכיוון שהן שוות!)
- צרו קואורדינטה שלישית עם x:
3ו-y:7, והוסיפו אותה לקבוצה - הדפיסו את האורך הסופי של הקבוצה
- צרו שני אובייקטים נפרדים מסוג
האתגר הזה מדגים מדוע יש לדרוס תמיד יחד את hashCode ואת ==. ה-Set משתמש בקודי גיבוב כדי לארגן איברים, ולכן ללא hashCode מתאים, אפילו אובייקטים שווים עלולים להישמר ככפילויות!
פלט צפוי:
true
false
1
2נסו בעצמכם
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: הדפיסו את הגודל הסופי של הקבוצה
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםספריות וייבואמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותמשתני מופעיסודות הבנאיחזרה: מחשבון פשוט4בטיחות מפני ערכי null
מבוא לבטיחות מפני ערכי nullניתן להקצאה ל-null לעומת לא ניתן להקצאה ל-nullהאופרטורים ? ו-!מילת המפתח Late ובטיחות מפני ערכי nullאופרטורים מודעי nullבטיחות מפני ערכי null במחלקותסיכום – מערכת פרופילי משתמשים7מחלקות מופשטות וממשקים
מחלקות מופשטותמתודות מופשטותממשקים ב-Dartממשקים משתמעיםמימוש לעומת הורשהממשקים מרוביםחזרה – מחשבון צורות10אוספים וגנריות
סקירה כללית של List, Set ו-Mapאוספים בטוחים מבחינת טיפוסיםמחלקות גנריותמתודות גנריותאילוצים גנרייםIterable ו-Iteratorסיכום – אחסון גנרי13מושגי OOP מתקדמים
הרכבה לעומת הורשהמתודות הרחבהמחלקות קריאותמחלקות אטומות (Dart 3)רשומות (Dart 3)תבניות והתאמה (3.0)טיפוסים מונים עם מתודות16פרויקט: ניהול ספרייה
סקירת הפרויקטמחלקות ספר ומשתמש2בנאים ב-Dart
בנאי ברירת מחדלבנאים בעלי שםרשימות אתחולבנאים קבועיםבנאי Factoryבנאים מפניםסיכום - בונה צורות5כימוס
חברים ציבוריים לעומת פרטייםמוסכמת הקידומת _פרטיות ברמת הספרייההעמקה ב-getters וב-settersהסתרת מידעסיכום – רשומות תלמידים8מיקסינים
מבוא למיקסיניםיצירת מיקסיניםשימוש במספר מיקסיניםמילת המפתח on במיקסיניםמיקסינים לעומת ירושהמיקסינים לעומת ממשקסיכום – מערכת בעלי החיים11מתודות מיוחדות
דריסת toString()דריסת hashCode ו־==הממשק Comparableמתודת call()דריסת noSuchMethodסיכום – אוסף מותאם אישית3מאפייני מחלקה
איברי מופע לעומת איברים סטטייםשדות final ו-constמשתני lateמתודות ושדות סטטייםGetters ו-Settersסיכום – מנהל חשבונות בנק6ירושה
ירושה בסיסיתמילת המפתח superדריסת מתודותהאנוטציה @overrideמילת המפתח final למחלקהבנאים וירושהסיכום – היררכיית עובדים9פולימורפיזם
יסודות הפולימורפיזםפולימורפיזם באמצעות ממשקיםבדיקת טיפוסים בזמן ריצההאופרטורים is ו-asמילת המפתח קווריאנטיסיכום — מעבד תשלומים12תכנות מונחה עצמים אסינכרוני
Future-ים ו-async/awaitיסודות ה-Streamsבקרי Streamsבנאים אסינכרונייםאסינכרוניות במתודות של מחלקהסיכום - אחזור נתוניםתרגלו בעצמכם: קומפיילר Dart אונליין