5

抽象基本クラスから継承する2つのケースクラスがあります。継承するケースクラスのコピーメソッドを使用する(したがって、子クラスのインスタンスを返す)抽象基本クラスにいくつかのメソッドを定義したいのですが、自己型を使用してこれを行う方法はありますか?

コード例:

abstract class BaseClass(a: String, b: Int) {
  this: case class => //not legal, but I'm looking for something similar

  def doubleB(newB: Int) = this.copy(b = b * 2) //doesn't work because BaseClass has no copy
}

case class HasC(a: String, b: Int, c: Boolean) extends BaseClass(a, b) {
  def doesStuffWithC(newC: Boolean) = {
    ...
  }
}

case class HasD(a: String, b: Int, D: Double) extends BaseClass(a, b) {
  def doesStuffWithD(newD: Double) = {
    ...
  }
}

この質問のおかげで、私が望む結果を得る方法を理解しました: Scalaのこの型付け、抽象型などを使用してSelf型を実装するにはどうすればよいですか? ただし、makeCopyメソッドをBaseClassに追加し、各子ケースクラスでcopyを呼び出すことでオーバーライドする必要があり、構文(特にSelfタイプの場合)はかなり混乱します。Scalaに組み込まれているセルフタイピングでこれを行う方法はありますか?

4

3 に答える 3

5

copy 考えられるすべてのパラメータについて知る必要があるため、やりたいことを行うことはできません。したがって、から継承されたケースクラスであっても、必要なCopyableものではありません。copyまた、型をまっすぐに保つつもりなら、Scalaの" MyType"の欠如に邪魔されるでしょう。したがって、基本クラスを拡張することはできませんただし、抽象メソッドとタイプアノテーションを追加することはできます。

abstract class BaseClass[C <: BaseClass[_]](a: String, b: Int) {
  def setB(b0: Int): C
  def doubleB(b0: Int) = setB(b0*2)
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass[HasC](a,b) {
  def setB(b0: Int) = this.copy(b = b0)
  def doesStuffWithC(c0: Boolean) = doubleB(if (c0) b else -b).copy(c = c0)
}

そして、次のことができます。

scala> HasC("fish",1,false).doesStuffWithC(true)
res47: HasC = HasC(fish,2,true)

bこの余分な作業は、コピーする機能(多くのメソッドまたは少数の複雑なメソッド)に依存する多くの共有機能がある場合に価値があります。つまり、これによりDRYの問題が解決されます。代わりに、他の派生クラスを抽象化する場合は、タイプのパラメーター化を定義する、または単に忘れて戻りタイプとして使用するさらに別のレベルをHasC使用または追加できます(ただし、メソッドを使用できず、タイプIDを保持できることを認識してください)。BaseClass[_]setB(b0: Int): BaseBaseBaseClassHasCBaseClass

于 2012-04-24T20:24:39.583 に答える
1

運が悪いと思います。上のcopyメソッドHasCHasDは異なるシグネチャを持っています。デフォルトの引数のために少し隠されていますが、基本的にの定義はどのメソッドを呼び出すBaseClassかを知りません。copy

于 2012-04-24T20:17:27.630 に答える
1

Unitを受け取りBaseClassを返すコピー機能を受け取る抽象クラスでmakeCopyを定義し、それを使用するメソッド(doubleBなど)でcaseクラス本体でそれらをオーバーライドし、makeCopyを渡すことで使用できます。次のように、小道具を変更して新しいコピーを作成する作業を行う無名関数:

package delegatedcopy

abstract class BaseClass(a: String, b:Int){
  def aField = a
  def bField = b
  def doubleB:BaseClass
  def makeCopy(copier: () => BaseClass):BaseClass = copier()
}

case class HasC(override val aField: String, override val bField: Int, cField: Boolean) extends BaseClass(aField, bField){
  override def doubleB:BaseClass = makeCopy( ()=> HasC(aField, bField * 2, cField) )
}

case class HasD(override val aField: String, override val bField: Int, dField:Double) extends BaseClass(aField, bField){
  override def doubleB:BaseClass = makeCopy( ()=> HasD(aField, bField * 2, dField) )
}

それを実証するテストアプリ:

import delegatedcopy._

object TestApp extends Application{
  val hasC = HasC( "A C object", 5, true)
  val hasD = HasD( "A D object", 2, 3.55)
  val hasCDoubleB = hasC.doubleB
  val hasDDoubleB = hasD.doubleB

  println(hasC) // prints HasC(A C object,5,true)
  println(hasCDoubleB) //prints HasC(A C object,10,true)

  println( hasD ) // prints HasD(A D object,2,3.55)
  println( hasDDoubleB ) // prints HasD(A D object,4,3.55)
}

このようにして、makeCopyメソッドをすべての子クラスで基本クラスと同じに保つことができ、共通のコードを安全な場所に保ちながら、基本クラスとケースクラスにかなりの機能を実装または混在させることができます。特定のケースクラスでBaseClassとパターンマッチをクライアントに渡すことができます。

于 2012-04-25T13:36:47.430 に答える