الفرق بين المراجعتين لصفحة: «Kotlin/data classes»
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE:أصناف البيانات (Data Classes) في لغة Kotlin}}</noinclude> تُنشَأ بعض الأصناف بهدف تخزين البيان...' |
طلا ملخص تعديل |
||
سطر 17: | سطر 17: | ||
وبما يخصُّ وراثة العناصر (members inheritance) فيجب التقيُّد بالقواعد الآتية: | وبما يخصُّ وراثة العناصر (members inheritance) فيجب التقيُّد بالقواعد الآتية: | ||
* إذا وُجِد تعريف استخدام (implementation) الدوال <code>equals()</code> أو <code>hashCode()</code> أو <code>toString()</code> في صنف البيانات أو إعادة تعريف استخدامٍ من النوع <code>final</code> في الصنف الأعلى (superclass) فإنّ هذه الدوال لا تُولَّد (generated) بل تُستخدم تعريفاتها الموجودة. | * إذا وُجِد تعريف استخدام (implementation) الدوال <code>equals()</code> أو <code>hashCode()</code> أو <code>toString()</code> في صنف البيانات أو إعادة تعريف استخدامٍ من النوع <code>final</code> في الصنف الأعلى (superclass) فإنّ هذه الدوال لا تُولَّد (generated) بل تُستخدم تعريفاتها الموجودة. | ||
* إذا احتوى النوع الأعلى (supertype) على دوال <code>componentN()</code> المفتوحة (من النوع <code>open</code>) والتي تعيد أنواعًا متوافقة، حينها تُولَّد الدوال المُوافقة في صنف البيانات ويُعاد تعريف (override) تلك الدوال في النوع الأعلى، وإذا لم يكن من الممكن إعادة تعريفها بسبب كونها <code>final</code> أو عدم التوافق في | * إذا احتوى النوع الأعلى (supertype) على دوال <code>componentN()</code> المفتوحة (من النوع <code>open</code>) والتي تعيد أنواعًا متوافقة، حينها تُولَّد الدوال المُوافقة في صنف البيانات ويُعاد تعريف (override) تلك الدوال في النوع الأعلى، وإذا لم يكن من الممكن إعادة تعريفها بسبب كونها <code>final</code> أو عدم التوافق في ترويستها (signature) فسينتُج خطأ عن ذلك. | ||
* يُحدُّ في Kotlin 1.2 من اشتقاق صنف البيانات من نوعٍ يحتوي على دالة copy(...) وبتأشيرةٍ متوافقةٍ (matching signature) وسيُمنع ذلك بدءًا من الإصدار Kotlin 1.3. | * يُحدُّ في Kotlin 1.2 من اشتقاق صنف البيانات من نوعٍ يحتوي على دالة copy(...) وبتأشيرةٍ متوافقةٍ (matching signature) وسيُمنع ذلك بدءًا من الإصدار Kotlin 1.3. | ||
* لا يُسمح بوجود تعريف الاستخدام (implementation) الصريح لأيّ من الدالتين <code>componentN()</code> و <code>copy()</code>. | * لا يُسمح بوجود تعريف الاستخدام (implementation) الصريح لأيّ من الدالتين <code>componentN()</code> و <code>copy()</code>. |
مراجعة 12:54، 25 مارس 2018
تُنشَأ بعض الأصناف بهدف تخزين البيانات فيها بشكلٍ أساسيّ، وبالتالي فإنّ كلّ ما تقوم به هذه الأصناف من وظائف يرتبط بالبيانات، وهذا ما يُسمى بأصناف البيانات في لغة Kotlin وتُعرَّف بالمُحدِّد data
كما يلي:
data class User(val name: String, val age: Int)
قواعد عامّة
يقوم المُترجِم في الأصناف من هذه النوع باشتقاق العناصر (deriving members) الآتية من كلِّ الخاصّيّات المُعرَّفة في الباني الأساسيّ (primary constructor):
- كلًا من
equals()
وhashCode()
- الدالة
toString()
بشكلها"User(name=John, age=42)"
- الدوال بالصيغة
componentN() functions
بما يتناسب مع الخاصّيّات وترتيبها أثناء التصريح - الدالة
copy()
ويجب أن تُحقِّق أصناف البيانات الشروط الآتية لضمان الترابط والسلوك الفعّال في الشيفرة المُولَّدة:
- أن يحتوي الباني الأساسيّ (primary constructor) على متحولٍ (parameter) واحدٍ على الأقل
- أن تكون متحولاته إمّا من النوع
var
أو النوعval
- ألّا يكون الصنف من النوع
abstract
أوopen
أوsealed
أوinner
- يمكن للصنف إعادة تعريف استخدام (implement) الواجهات (interfaces) فقط (هذا قبل الإصدار 1.1)
وبما يخصُّ وراثة العناصر (members inheritance) فيجب التقيُّد بالقواعد الآتية:
- إذا وُجِد تعريف استخدام (implementation) الدوال
equals()
أوhashCode()
أوtoString()
في صنف البيانات أو إعادة تعريف استخدامٍ من النوعfinal
في الصنف الأعلى (superclass) فإنّ هذه الدوال لا تُولَّد (generated) بل تُستخدم تعريفاتها الموجودة. - إذا احتوى النوع الأعلى (supertype) على دوال
componentN()
المفتوحة (من النوعopen
) والتي تعيد أنواعًا متوافقة، حينها تُولَّد الدوال المُوافقة في صنف البيانات ويُعاد تعريف (override) تلك الدوال في النوع الأعلى، وإذا لم يكن من الممكن إعادة تعريفها بسبب كونهاfinal
أو عدم التوافق في ترويستها (signature) فسينتُج خطأ عن ذلك. - يُحدُّ في Kotlin 1.2 من اشتقاق صنف البيانات من نوعٍ يحتوي على دالة copy(...) وبتأشيرةٍ متوافقةٍ (matching signature) وسيُمنع ذلك بدءًا من الإصدار Kotlin 1.3.
- لا يُسمح بوجود تعريف الاستخدام (implementation) الصريح لأيّ من الدالتين
componentN()
وcopy()
.
ويُسمَح بدءًا من الإصدار 1.1 أن تكون أصناف البيانات إضافةً (extend) للأصناف الأخرى. (راجع الأصناف المغلقة [sealed classes] للحصول على الأمثلة)
وإذا تطلَّب الصنف المُولَّد في JVM أن يحتوي على بانٍ بدون متحولات (parameterless) فيجب حينئذٍ تحديد القيم الافتراضيّة لكافّة الخاصّيّات كما في الشيفرة: (راجع البواني [constructors])
data class User(val name: String = "", val age: Int = 0)
الخاصيات (Properties) المُعرَّفة في بنية الصنف (Class Body)
يَستخدِم المُترجِم الخاصّيّات المُعرَّفة داخل الباني الأساسيّ (primary constructor) للدوال المولَّدة تلقائيًا فقط، وبالتالي فإنه لاستبعاد أيّ خاصّيّة من تعاريف الاستخدام (implementations) المُولَّدة، يجب تعريفها في بُنية الصنف، مثل:
data class Person(val name: String) {
var age: Int = 0
}
ففي الشيفرة السابقة يُسمَح باستخدام الخاصية name
فقط في أيّ من الدوال equals()
و hashCode()
و toString()
و copy()
وسيكون هناك دالة واحد للعناصر (component function) باسم component1()
، وعلى الرغم من أنّه يمكن أن يكون لكائنين من النوع Person
أعمارٌ مختلفةٌ فإنها ستُعامَل وكأنها متساوية، جرِّب الشيفرة الآتية:
val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
إذ يُعدُّ الشرط: person1 == person2
بقيمة true
.
دالة النسخ copy()
قد تحتاج في حالاتٍ كثيرة إلى استنساخ كائنٍ ما (object) والتعديل في "بعض" خاصّيّاته (properties) مع المحافظة على الأخرى كما هي بدون تعديل، وهذا ما تقوم به الدالة copy()
، ففي الصنف السابق User
سيكون تعريف استخدام (implementation) الدالة كما يلي:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
وهذا سيُتيح الاستخدام الآتي في الشيفرة:
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
أصناف البيانات وتفكيك التصريحات (Destructuring Declarations)
تُولَّد دوال العناصر (component functions) بهدف استخدامها في تفكيك التصريحات في أصناف البيانات، كما في الشيفرة الآتية:
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // ستظهر العبارة "Jane, 35 years of age"
أصناف البيانات القياسيّة (Standard Data Classes)
توفّر المكتبة القياسيّة الصنفين Pair
و Triple
لأنّ استخدام أصناف البيانات المُسماة يكون -في معظم الأحيان- خيارًا أفضل، لأنّها تجعل الشيفرة أسهل قراءةً عبر تزويدها بأسماءٍ معبِّرةٍ للخاصّيّات.