1

Printerフィルターを通過できない場合を除き、提供された引数を出力 する抽象クラス (これは類似の例です)があります。Printerそのジェネリック型に対して反変Tです。

class Printer[-T] {
  val filters: Seq[Function2[T => Boolean]]

  def print(t: T): Unit {
    if (filters.forall(_(t))) doPrint(t)
  }
  def doPrint(t: T): Unit
}

現在、20 個のサブクラスがありPrinterます。1 つは String、Int などPrinterです。 は反変でfiltersあるため、val. ただしPrinter、フィルターを追加するメソッドが必要な場合は、不変である必要があります。

def addFilter[TT <: T](t: TT): Printer[TT]

残念ながら、20 個のサブクラスのそれぞれにこのメソッドを実装する必要があります。これを回避する方法はありますか?

更新: また、addFilterでは、スーパークラスの代わりにサブクラスを返す方法がわかりませんPrinter。たとえば、 a を呼び出しaddFilterた場合、StringPrinter理想的には型を取得しStringPrinterます。

4

1 に答える 1

1

以下は、あなたがコード化した方法から少し離れていますPrinterが、潜在的にあなたの意図を満たすことができます. クラスをコーディングするこの方法により、懸念事項をより分離できることに注意してください。使用方法とは関係なく、フィルターを定義して実装 (doPrint引数)を出力できます。

case class Printer[T](val filters: List[Function1[T, Boolean]], val doPrint: T => Unit) {
  def print(t: T): Unit = {
    if (filters.forall(_(t))) doPrint(t)
  }

  def addFilter[TT <: T](f: TT => Boolean): Printer[TT] = copy(f :: filters)
}

ここで反変性を指定する必要はないことに注意してください。それが問題になるかどうかはわかりません。

クラスを使用するには、サブクラス化する必要はありません。適切な引数をコンストラクターに渡すだけです (実際には、applyケース クラス用に無料で提供されているコンパニオン ファクトリ メソッド)。

case class Foo(x: Int)
val fooChk1: Foo => Boolean = (f: Foo) => f.x != 1
val fooPrinter1 = Printer(fooChk1 :: Nil, (f: Foo) => println(s"Foo: x = ${f.x}"))

val fooChk3: Foo => Boolean = (f: Foo) => f.x != 3
val fooPrinter2 = fooPrinter1.addFilter(fooChk3)

val foo3 = Foo(3)
fooPrinter1.print(foo3) // Prints 'Foo: x = 3'
fooPrinter3.print(foo3) // Prints nothing

ここでも暗黙を使用するためのかなりの範囲があります-パラメーターの両方Print(たとえば、コンストラクターをに変更(val filters: List[Function1[T, Boolean]])(implicit val doPrint: T => Unit))と特定Print[X]のバリアントの両方。

于 2013-10-17T03:24:30.707 に答える