読者です 読者をやめる 読者になる 読者になる

算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

Kotlin M13で追加されたsealed class

Kotlin マイルストーン13 がリリースされました!

blog.jetbrains.com

lateinit修飾子については↓の記事をば。

Kotlin M13で追加されたlateinit試してみた - 算譜王におれはなる!!!!

sealed class

クラスに付けられるsealed修飾子が追加されました。 一言で言うと、クラスの継承を制限するための修飾子です。 sealedが付いたクラスを継承するにはある条件を満たす必要があるということです。 そういう意味でScalasealedと似ていてC#のそれとは異なります。

肝心のsealed classを継承するための条件ですが、現時点ではsealed classにネストされたクラスであることです。

sealed class A {
  class B: A()
}

class C: A() // これはダメ

そのうち、この制限を緩和して同一ソースファイル内での継承も許可するそうです。

さて、このsealed classですが何の役に立つのかと言うと、リリースノート内でAlgebraic Data Types(代数的データ型)というキーワードが登場しています。 例えば列挙型をenum classではなくsealed classとそのサブクラスで表現可能です。

sealed class Color {
  object Red:   Color()
  object Green: Color()
  object Blue:  Color()
}

val name = when(color) {
  Color.Red   -> "赤"
  Color.Green -> "緑"
  Color.Blue  -> "青"
}

when式の分岐でelseがないことに注目してください。 Colorsealed classとして定義されており、他の場所でそのサブクラスが定義されないことを保証します。 そのためwhen式の分岐でRedGreenBlueすべての場合が考慮されていることをコンパイラは知っているのでelseが不要になります。 Coloropen classとして定義された場合には、他の場所でもそのサブクラスが定義される可能性があるのでコンパイラはwhen式にelseを要求します。

次に、sealed classを使って直和型を表現してみます。

import Option.*

sealed class Option<out T> {
  class Some<T>(val value: T): Option<T>()
  object None: Option<Nothing>()
}

val name = when (userOption) {
  is Some<User> -> userOption.value.name
  is None       -> "null"
}

便利ですね〜。 ちなみにインタフェースにはsealedを付けられないみたいです。