[英]Scala copy method in supertype
I have an abstract class (this is an analogous example) Printer
which prints the supplied argument unless it fails to pass a filter. 我有一个抽象类(这是一个类似的示例) Printer
,它打印提供的参数,除非它没有通过过滤器。 Printer
is contravariant wrt its generic type T
. 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
}
I now have 20 subclasses of Printer
-- one for Strings, Ints, etc. Since Printer
is contravariant, filters
must be a val
. 现在,我有20个Printer
子类-一个用于String,Ints等。由于Printer
是互变的,所以filters
必须是val
。 However if I want a method of Printer
to add a filter it needs to be immutable. 但是,如果我想让Printer
的方法添加过滤器,则它必须是不可变的。
def addFilter[TT <: T](t: TT): Printer[TT]
Unfortunately I now need to implement this method in each of my 20 subclasses. 不幸的是,我现在需要在我的20个子类中的每一个中实现此方法。 Is there any way around this? 有没有办法解决?
Update: Also, in addFilter
, I don't know how I can return the subclass instead of the superclass Printer
. 更新:另外,在addFilter
,我不知道如何返回子类而不是超类Printer
。 For example, if I called addFilter
on a StringPrinter
I would ideally get the type StringPrinter
back. 例如,如果我在StringPrinter
上调用addFilter
,则理想情况下将返回StringPrinter
类型。
THe following is a bit of a departure from the way you have coded your Printer
, but potentially could fulfil your intentions. 以下内容与您对Printer
进行编码的方式有些偏离,但可能会实现您的意图。 Note that this way of coding your class enables a greater separation of concerns: you can define filters and print implementations (the doPrint
argument) independently of how they are being used: 请注意,这种对类进行编码的方式可以实现更大的关注点分离:您可以独立于使用方式来定义过滤器和打印实现( 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)
}
Note that I haven't needed to specify contravariancy here, not sure if that will be an issue for you. 请注意,我并不需要在这里指定矛盾性,不确定是否会给您带来麻烦。
To use the class, you don't need to subclass, just pass suitable arguments into the constructor (actually, the companion apply
factory method provided for free for case classes) - eg: 要使用该类,您不需要子类化,只需将适当的参数传递给构造函数(实际上,同伴为case类免费提供了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
There is also a fair bit of scope for using implicits here, too - both for parameters to Print
(eg. change the constructor to (val filters: List[Function1[T, Boolean]])(implicit val doPrint: T => Unit)
), and for specific Print[X]
variants. 在这里使用隐式也有相当大的范围-都可以Print
参数(例如,将构造函数更改为(val filters: List[Function1[T, Boolean]])(implicit val doPrint: T => Unit)
),以及特定的Print[X]
变体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.