Dart / التكامل: الأهداف والموارد والتحقق والأدلة / الدرس 16
بناء نماذج قيم بمساواة مستقرة ولقطات واضحة
نفّذ المساواة وhashCode معا، وثبّت المفاتيح، واختر سياسات نسخ وحاويات غير قابلة للتعديل صراحة.
في هذه الصفحة
أهداف الدرس
- اشرح لماذا لا تمنح حقول final والكائنات المتشابهة شكلا مساواة قيمية تلقائيا.
- راجع المساواة والتجزئة والنسخ والتعديل الداخلي كعقد واحد لنموذج البيانات.
اختر ما يجعل مثيلين القيمة نفسها
تعتمد مثيلات أصناف Dart العادية مساواة الهوية ما لم يعرّف الصنف عقدا آخر. قد يبدو تمثيلان لمفهوم تطبيق متطابقين في المصحح ولا يتساويان. حدّد حقول القيمة: ربما يشكل معرف العينة ومراجعتها مفتاحا، بخلاف عنوان عرض مؤقت. تقدم سجلات Dart مساواة تركيبية وفق عقود حقولها، لكن القوائم العادية لا تقارن عناصرها تلقائيا واحدا بواحد. اختر النموذج المقصود صراحة، ولا تفترض أن final أو منشئا يبدو مولدا يقدمان مساواة عميقة.
يجب أن تتفق المساواة والتجزئة
إذا تساوى كائنان وجب تساوي hashCode، ولا يصح العكس؛ فقد يحدث تصادم تعالجه مساواة الحاوية. يستخدم المفتاح حقلي نص وصحيح ثابتين وObject.hash. يطبع علاقات المساواة لا رقما محددا، لأن قيم التجزئة ليست معرفات عمل دائمة ولا يلزم ثباتها عبر التشغيل والمنصات. يجب أن تحفظ المساواة المخصصة خصائصها كالتناظر والتعدي. وتحتاج تسلسلات قيم قابلة للامتداد عناية خاصة عندما تضيف الأنواع الفرعية حقولا أو تغير المساواة.
final class SampleKey {
final String id;
final int revision;
const SampleKey(this.id, this.revision);
@override
bool operator ==(Object other) =>
other is SampleKey && other.id == id && other.revision == revision;
@override
int get hashCode => Object.hash(id, revision);
}
void main() {
final first = SampleKey('S-4', 1);
final equalValue = SampleKey('S-4', 1);
print(first == equalValue);
print(first.hashCode == equalValue.hashCode);
print(<SampleKey>{first, equalValue}.length);
}
true
true
1
المخرج المتوقع true ثم true ثم 1. تحتل المفاتيح المتساوية عنصرا واحدا في Set. لا يُتوقع رقم تجزئة معين، ولم يُترجم المصدر أو ينفذ.
قد يفسد مفتاح معدل افتراضات البحث بالتجزئة
قد يغير تعديل حقل تحدده المساواة أو hashCode بعد الإدراج سلوك حاوية التجزئة خلاف التوقع. وضعت الحاوية الكائن بتجزئته السابقة، وتواجه القراءة لاحقا عقد قيمة مختلفا. لا تصلح ذلك بالإعادة أو باعتبار الفقد خللا عشوائيا في البنية. استخدم مفاتيح ثابتة أو أزل وأعد الإدراج بسياسة مقصودة إذا لزم التعديل فعلا. ويظل حقل final يحمل قائمة معدلة خطرا إذا اعتمدت مقارنة مخصصة على محتواها المتغير.
انسخ الحاوية وفقا لوعد ملكيتها
ينشئ منشئ اللقطة قائمة غير قابلة للتعديل من التسميات. لا تغير إضافات المصدر اللاحقة بنية تلك القائمة. وتبني النسخة المعدلة تسلسلا جديدا بدلا من تحرير اللقطة القديمة. تجعل النصوص المثال مباشرا؛ وتحتاج عناصر كائنية معدلة ملكية أو نسخا خاصين. لا يتجاوز الصنف المساواة، فلا تتساوى اللقطات تلقائيا بالمحتوى. افصل عزل المحتوى عن مساواة المثيلات، واشرحهما عند عرض النموذج للتخزين المؤقت أو حامل حالة أو غيره.
class BatchSnapshot {
final String id;
final List<String> labels;
BatchSnapshot(this.id, Iterable<String> labels)
: labels = List<String>.unmodifiable(labels);
BatchSnapshot withLabel(String label) =>
BatchSnapshot(id, <String>[...labels, label]);
}
void main() {
final source = <String>['raw'];
final first = BatchSnapshot('B-3', source);
source.add('external');
final second = first.withLabel('reviewed');
print(first.labels.join('|'));
print(second.labels.join('|'));
}
raw
raw|reviewed
المخرج المتوقع raw ثم raw|reviewed. لا تظهر إضافة المصدر الخارجية في اللقطتين لأن المنشئ الأول نسخ بنية القائمة. لم يُنفذ البرنامج.
تحقق من النموذج عند الحد الذي يُوثق فيه
لا يثبت الثبات إيجابية العدد أو تفويض المعرف أو وجود المراجعة. تحقق من القواعد منفصلة. لا تستخدم toString أو hashCode هوية مسلسلة؛ فغرضهما مختلف عن رمز نقل مستقر. افحص تعديل المراجع ومساواة مثيلين مستقلين واختلاف القيم واتساق التجزئة معزولا بالأدوات الفعلية. وإذا عبر النموذج عوازل أو JSON فراجع النقل والفك مستقلا. لم يُشغّل هنا اختبار مساواة أو تجربة تعديل؛ والأمثلة برامج تعليمية محللة.
الأخطاء الشائعة وإصلاحها
تنتج كائنات متساوية تجزئات مختلفة.
- لماذا يحدث؟
- لم يقترن تجاوز == بتنفيذ hashCode متسق.
- كيف تصلحه؟
- استخدم حقول القيمة نفسها للعقدين.
- كيف تتجنب تكراره؟
- افحص مثيلين مستقلين متساويين واتساق تجزئتهما معا.
يتغير حقل قائمة final عبر مرجع المصدر.
- لماذا يحدث؟
- خزن النموذج حاوية معدلة مشتركة بلا سياسة لقطة.
- كيف تصلحه؟
- انسخ أو غلف بالواجهة المناسبة وراجع تعديل العناصر.
- كيف تتجنب تكراره؟
- اختبر تعديل المصدر بعد بناء النموذج.
لا تعرّف تجزئة محفوظة السجل المتوقع لاحقا.
- لماذا يحدث؟
- استُخدمت أداة تجزئة تشغيل هوية عمل دائمة.
- كيف تصلحه؟
- احفظ معرفا صريحا مستقرا وتحقق منه عند الحد.
- كيف تتجنب تكراره؟
- افصل مساعدات المساواة عن معرفات التخزين والنقل.
اختبر فهمك
1. هل يثبت تطابق hashCode مساواة كائنين؟
اعرض الحل المشروح
لا. قد تتصادم قيم مختلفة. تستخدم حاوية التجزئة المساواة أيضا للتمييز. المطلوب أن تتساوى تجزئات القيم المتساوية، لا أن تعني كل تجزئتين متساويتين قيمة واحدة. لا تستخدم hashCode وحدها قرار تفويض أو مفتاحا فريدا أو بصمة دائمة.
2. تحتوي لقطة كائنات عينات قابلة للتعديل. هل يكفي نسخ قائمتها الخارجية؟
اعرض الحل المشروح
فقط إذا سمح العقد بتغير العناصر المشتركة لاحقا. وإلا فاستخدم قيما ثابتة أو نسخا أعمق صريحا أو ملكية حصرية. حدّد الهوية التي يجب حفظها ومعالجة عناصر تملك موارد. لا يحسم شعار النسخ العميق العام مسائل المجال والعمر.
أهم ما تعلمته
- تشكل مساواة القيمة واتساق التجزئة وثبات المفتاح عقدا واحدا.
- يجب أن تفسر اللقطة ملكية الحاوية والعناصر معا.