超类型中的Scala复制方法

时间:2013-10-17 01:14:08

标签: scala

我有一个抽象类(这是一个类似的例子)Printer,它打印提供的参数,除非它无法通过过滤器。 Printer是逆变的w.r.t.它的通用类型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子类 - 一个用于字符串,Ints等。由于Printer是逆变的,filters必须是val。但是,如果我想要一个Printer的方法来添加过滤器,那么它需要是不可变的。

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

不幸的是,我现在需要在我的20个子类中的每个子类中实现此方法。有没有办法解决这个问题?

更新:此外,在addFilter中,我不知道如何返回子类而不是超类Printer。例如,如果我在addFilter上调用了StringPrinter,我理想情况下会返回StringPrinter类型。

1 个答案:

答案 0 :(得分: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]变量