الأصناف المُغلَقة (Sealed Classes) في لغة Kotlin
تُستخدَم الأصناف المُغلَقة لتمثيل الهرميّة (hierarchy) المحدودة للأصناف؛ وذلك عندما يكون نوع القيمة هو أحد الأنواع الموجودة في مجموعةٍ مُحدَّدةٍ (limited set) وليس أيّ نوع آخر، وبالتالي تُعدُّ هذه الأصناف إضافةً (extension) لأصناف الثوابت المُتعدَّدة (enum classes)، إذ إنّ مجموعة القيم لنوع enum
محدودة أيضًا ولكل ثابت فيها نسخةٌ (instance) واحدةٌ فقط، بينما يمكن أن يكون للصنف الفرعيّ (subclass) من الصنف المغلق أكثر من نسخةٍ تحتوي على الحالة (case).
ويُستخدَم المُحدِّد (modifier) sealed
قبل اسم الصنف للتصريح عن أنّه من النوع المُغلَق، ويمكن أن يكون له عدّة أصنافٍ فرعيةٍ (subclasses) بشرط أن تكون مُعرَّفةً ضمن نفس الملف الذي يُوجد فيه، وكانت القواعد صارمةً أكثر قبل الإصدار Kotlin 1.1 حيث كان من اللازم أن تتداخل (nested) تلك الأصناف مع تعريف الصنف المغلَق.
مثل:
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
تستفيد الشيفرة السابقة من ميّزة أخرى للإصدار 1.1 وهي إمكانيّة جعل أصناف البيانات (data classes) إضافةً (extend) للأصناف الأخرى بما فيها الأصناف المغلَقة.
ويُعدُّ الصنف المغلَق مُجرَّدًا (abstract) بحدِّ ذاته، وبالتالي فإن عناصره من النوع abstract
ولا يُمكِن إنشاء كائنٍ (instance) منه بشكلٍ مباشر، ولا يسمح كذلك لبواني (constructors) الأصناف المغلَقة أن تكون من غير النوع الخاصّ (private
) فهو النوع الافتراضيّ لها.
ويمكن للأصناف التي تكون إضافةً (extend) للأصناف الفرعية (subclasses) من الصنف المغلَق (وراثةٌ غير مباشرةٍ) أن تكون في أيّ مكان ولا يُشتَرط أن تكون في نفس الملف (file).
والميّزة الأهمُّ لاستخدام الأصناف المغلَقة تكمُن في استخدامها في تعبير when
، فإذا أمكن التأكُّد بأنّ التعليمة تشمل كافّة الحالات المُمكنة فليس من الضروري حينئذٍ إضافة الحالة else
، ولكن هذا ينطبق فقط إذا كانت تعليمة when
تعبيرًا (expression) (بالاستفادة من النتيجة) وليست تعلمية (statement)، مثل:
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// تشمل الحالات السابقة كافة الحالات الممكنة لذلك لا داعي لوجود else
}