Kotlinデータクラスと封印されたクラス
データ・タイプ
Kotlinは、データのみを含むクラスを作成できます。キーワードはdataです。
data class User(val name: String, val age: Int)
コンパイラーは、宣言されたすべての属性に基づいて、メインコンストラクターから次の関数を自動的に抽出します。
equals()
/hashCode()
toString()
次のような形式"User(name=John, age=42)"
componentN() functions
宣言順に並べられた属性に対応copy()
関数
これらの関数がクラスで明確に定義されているか、スーパークラスから継承されている場合、それらは生成されなくなります。
生成されたコードの一貫性と意味を保証するために、データクラスは次の条件を満たす必要があります。
-
メインコンストラクターには、少なくとも1つのパラメーターが含まれています。
-
メインコンストラクターのすべてのパラメーターは、
val
またはvar
;としてマークする必要があります。 -
データクラスが宣言されていない
abstract
、open
、sealed
またはinner
; -
データクラスは他のクラスを継承できません(ただし、インターフェイスを実装できます)。
コピー
コピーするには、copy()関数を使用します。この関数を使用して、オブジェクトをコピーし、一部のプロパティを変更できます。上記のUserクラスの場合、実装は次のようになります。
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
インスタンス
copyクラスを使用して、Userデータクラスをコピーし、age属性を変更します
data class User(val name: String, val age: Int)
fun main(args: Array<String>) {
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
println(jack)
println(olderJack)
}
出力結果は次のとおりです。
User(name=Jack, age=1)
User(name=Jack, age=2)
データクラスと脱構築宣言
コンポーネント関数を使用すると、データクラスを宣言の破棄に使用できます
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
標準データクラス
標準ライブラリはペアとトリプルを提供します。ほとんどの場合、コードは読みやすく、意味のある名前と属性を提供するため、データクラスに名前を付ける方が設計上の選択として適しています。
封印
封印されたクラスは、制限されたクラス継承構造を表すために使用されます。値が限られた数の型であるが、他の型は存在できない場合。ある意味で、これらは列挙型クラスの拡張です。列挙型の値セットも制限されますが、各列挙型定数のインスタンスは1つだけであり、封印されたクラスのサブクラスは、例を含むことができるより多くの状態を持つことができます。 。
封印されたクラスを宣言し、sealedを使用してクラスを変更します。封印されたクラスはサブクラスを持つことができますが、すべてのサブクラスは封印されたクラスに埋め込まれている必要があります。
シールはインターフェイス、抽象クラスを変更できません(警告は報告されますが、コンパイルエラーは発生しません)
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
封印されたクラスを使用する主な利点は、when式を使用するときに、ステートメントがすべての状況をカバーしていることを確認できれば、ステートメントにelse句を追加する必要がないことです。
fun eval(expr: Expr): Double = when(expr) {
is Expr.Const -> expr.number
is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
Expr.NotANumber -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}