シールクラス(密閉クラス) : kotlin

シールクラス(密閉クラス)

シールクラスは限定的なクラス階層を表すために使用されます。
このクラスでは値は限定されたセットの型の1つを持つことができますが、それ以外の型を持つことが出来ません。

ある意味で、これらは列挙型クラスの拡張です。:
列挙型の値のセットも制限されますが、各列挙型定数は単一のインスタンスとしてのみ存在するのに対し、シールクラスのサブクラスは、状態を含むことができる複数のインスタンスを持てます。

シールクラスを宣言するには、クラス名の前にsealed修飾子を加えます。シールクラスはサブクラスを持つことができますが、それらはすべてシールクラス自体と同じファイルで宣言する必要があります。 (Kotlin 1.1より前は、ルールはさらに厳格でした。クラスは、シールクラスの宣言内にネストする必要がありました)。

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

(上記の例では、Kotlin 1.1で追加された新機能を利用しています。
データクラスがシールクラスを含む他のクラスを継承出来るようになりました。)

シールクラス自体は抽象クラスであり、直接インスタンス化は出来ず、抽象メンバを持てません。

シールクラスは、privateではないコンストラクタを持つことはできません。(それらのコンストラクタはデフォルトでprivateです)。

シールクラスのサブクラスを継承するクラス(間接継承)は、必ずしも同じファイル内ではなく、どこにでも配置できることに注意してください。

シールクラスを使用する主な利点は、when式で使用するときに役立ちます。ステートメントがすべてのケースをカバーしていることを確認できる場合は、ステートメントにelse句を追加する必要はありません。ただし、これはwhenをステートメントとしてではなく、式として使用(し、その結果を使用)する場合にのみ機能します。

fun eval(expr: Expr): Double = when(expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
    // 全てのケースをカバーしている為、`else`句は必要ありません。
}