1. 概要

最新のオブジェクト指向プログラミング言語は、単純で不変のデータを表すための抽象化を提供することがよくあります。 Scalaにはそのような抽象化があり、それは caseclassと呼ばれます。

このチュートリアルでは、Scalaのケースクラス、通常のクラスとの違い、およびそれらが提供する利点について学習します。

2. ケースクラス

ケースクラスの例を定義することから始めましょう:

case class CovidCountryStats(countryCode: String, deaths: Int, confirmedCases: Int)

デフォルトでは、すべてのコンストラクターパラメーターはパブリックで不変です。 それらをvarに変更できますが、それはそれらが設計されたものではありません。

ここで、コンストラクターパラメーターがデフォルトでプライベートである通常のクラスとの違いに気付くことができます。 Scalaのケースクラスの考え方は、Kotlinのデータクラスに似ているかもしれません。 また、Java 14では、recordsと呼ばれる同様の概念が導入されました。

それでは、ケースクラスのさまざまな機能を見てみましょう。

2.1. 短い初期化構文

短く簡潔な方法でケースクラスのインスタンスを作成できます。

val covidPL = CovidCountryStats("PL", 776, 15366)

newキーワードをスキップしたことに注意してください。 caseクラスには、コンパイラによって自動生成されたapply関数があるため、このような可能性があります。

ここで、ケースクラスをケースクラスにネストすることを想像してみましょう。 複雑なオブジェクトを読みやすい方法でインスタンス化できます。

2.2. パターンマッチング

パターンマッチングにより、クラスを適切に分解し、直感的なコードを記述できます。 これは間違いなく、ケースクラスで私たちが持っている最もクールな機能です:

covidPL matches {
    case CovidCountryStats("PL", x, y) => println("Death rate for Poland is " + x.toFloat / y.toFloat)
    ...
    case _ => println("Unknown country")
}

caseクラスには、デフォルトでコンパイラによって生成されたコンパニオンオブジェクトがあるため、このような構成が可能です。 コンパニオンオブジェクトには、前述の apply メソッドと、クラスをパターンマッチングできる unapplyextractorメソッドが含まれています。

2.3. 自動生成されたメソッド

Kotlinのデータクラスと同様に、Scalaのケースクラスは、hashcodeおよびequalsメソッドを自動的に定義しました。 また、デフォルトですべてのゲッターが定義されています。

ケースクラスは、適切なデフォルトのtoStringメソッドの実装も提供することを言及する価値があります。

2.4. 平等

通常のクラスとは対照的に、ケースクラスインスタンスは、参照ではなく構造によって比較されます。 以下のコードはtrueを生成します。

assert(CovidCountryStats("PL", 776, 15366) == CovidCountryStats("PL", 776, 15366))

CovidCountryStatsの定義からcaseキーワードを削除した場合、結果はfalseになります。

2.5. 製品

caseクラスはデフォルトでProductトレイトを拡張するため、いくつかのメソッドを継承します。

  • productElement(n:Int):任意、これはクラスのn番目のパラメーターを返します
  • productArity:Int 、これはいくつかのパラメーターを返します
  • productIterator:Iterator [Any] 、これによりパラメーターの反復が可能になります

ここに1つの制限があります— 製品特性を拡張するため、ケースクラスは22個を超えるパラメーターを持つことはできません。

2.7. コピー

ケースクラスには、デフォルトでcopyメソッドが生成されます。

val covidUA = covidPL.copy(countryCode = "UA")

コピーメソッドは浅いコピーのみを保証することに注意することが重要です。

2.8. 4倍

前述のapplyおよびunapplyメソッドとは別に、ケースクラスのコンパニオンオブジェクトはtupledメソッドを定義します。 tupled メソッドを使用すると、タプルからケースクラスオブジェクトを作成できます。

val tuple = ("PL", 776, 15366)
val covidPL = (CovidCountryStats.apply _).tupled(tuple)

2.9. 追加の考慮事項

ケースクラスを使用してコードを設計するときに知っておく必要のある別の制限があります。ケースクラスは別のケースクラスから継承できません。

caseクラスがSerializableを実装していることにも言及する価値があります。

3. 結論

この記事では、Scalaのケースクラスを詳しく見てきました。

それらがもたらす利点を説明し、通常のクラスと比較しました。 ご覧のとおり、ボイラープレートコードが大幅に削減されているため、単純なデータコンテナとして非常にうまく機能します。

ただし、このようにクリーンできちんとしたコードを作成するためのコストは、コンパイラーによって生成される追加の20のメソッドであり、おそらくこれを使用したくないことを認識しておく必要があります。

結局のところ、ケースクラスの機能は単なる構文糖衣です。 scalac -print コマンドを使用して、内部で正確に何が起こっているかを確認することをお勧めします。

いつものように、コード例はGitHubから入手できます。