2つのプロパティを定義する抽象クラスを考えてみましょう
abstract class A {
def a: Int
def b: Int
// real A has additional members
}
これは、次のようなさまざまなケースクラスの基本クラスです。
case class Foo(a: Int, b: Int) extends A
case class Bar(a: Int, b: Int) extends A
// and many more
目標:最終的に、前述のケースクラスのインスタンスを2つの方法で作成できるようにしたいと思います。
val b1 = Bar(1, 2)
val b2 = Bar(1) has 2
assert(b1 == b2) // must hold
アプローチ:したがって、 shas
を部分的に構築できるようにするヘルパークラスを定義することは合理的と思われます。A
case class PartialA(f: Int => A) {
def has(b: Int) = f(b)
}
問題:現在の機械では、のような呼び出しは許可されていませんBar(1)
。これは、実際には、の呼び出しBar.apply(1)
、つまりapply
、コンパイラによって生成されたオブジェクトによって定義されたメソッドの呼び出しであるためBar
です。
Bar
コンパイラにオブジェクトをとして生成させることができれば素晴らしいと思いますobject Bar extends PartialAConstructor
。
abstract class PartialAConstructor{
def apply(a: Int, b: Int): A // abstract, created when the compiler creates
// object Bar
def apply(a: Int) = PartialA((b: Int) => apply(a, b))
}
ただし、ケースクラスのコンパニオンオブジェクトの生成に影響を与えることはできないようです。
必要なプロパティ:
ケースクラス:などは、構造的同等性などのコンパイラで生成された機能と、自動生成されたエクストラクタを使用したいので、ケースクラスのままにする必要が
Foo
あります。Bar
copy
「完全な」構造的同等性:ケースクラスを次のように定義する
case class Bar(a: Int)(val b: Int)
コンパイラによって生成されたメソッドは引数の最初のリストのみを考慮するため、オプションではありません。
equals
したがって、次のことが誤って成立します。assert(Foo(1)(0) == Foo(1)(10))
コードの繰り返しをできるだけ少なくする:たとえば、もちろん、
def Bar(a: Int) = PartialA((b: Int) => Bar(a, b))
A
しかし、それは、Foo
拡張するすべてのケースクラスに対して実行する必要がありますBar
。