(Scala)如何从抽象类扩展apply方法?

时间:2016-07-13 02:34:41

标签: scala

我希望通过在基本抽象类中放置apply / unapply方法来在我的项目中保存大量代码。是不是可以在case类中编写apply方法,而是在抽象类中编写?

我在下面编写的代码实际上不起作用,但我相信它描述了我想要完成的任务。 Animal类中的apply方法不是将要编译的有效scala。

abstract class Animal(name:String,color:String,age:Int) {
  def apply(name:String, color:String, age:Int) = this(name,color,string) 
  def apply(name:String, color:String) = this(name,color,0) 
  def apply(name:String) = this(name,"",0) 
}

case class Rabbit(n:String,c:String,a:Int) extends Animal(n,c,a)
case class Squirrel(n:String,c:String,a:Int) extends Animal(n,c,a)
case class Dog(n:String,c:String,a:Int) extends Animal(n,c,a)
case class Cat(n:String,c:String,a:Int) extends Animal(n,c,a)

//(Ran elsewhere)
Rabbit("Billy")
Dog("Charlie","Brown",5)
Cat("Sprinkles","White")

1 个答案:

答案 0 :(得分:2)

首先,您希望apply方法位于随播对象上,而不是类本身,这样您就可以调用Rabbit(...),因为这是Rabbit.apply的糖。根据您拥有的内容,修复错误的this(...)调用,您需要Animal的实例才能调用apply方法。

其次,你似乎混淆了apply和构造函数。在Scala中,当您定义类时,名称旁边的参数定义主构造函数。然后,类的主体包含主构造函数的主体。您可以定义辅助构造函数,它们看起来就像方法定义一样,除了它们不返回任何内容并命名为this。这是一个辅助构造函数:

def this(qux: Qux) = {
  // Must call another constructor (super(...), this(...))
  this(qux.foobar)
  this.foo = qux.bar
}

您只能 使用new关键字调用构造函数(来自外部的另一个构造函数)。 没有其他方法可以调用构造函数。(除非,你调用一个调用构造函数(或反射(ew))的方法。)当你执行Foo(5)时,你不是不要直接调用构造函数,而是在伴随对象上调用Foo.apply(5)。对于普通类Bar,除非伴随对象定义了Bar(...)方法,否则apply将失败。

输入case class es。 Scala编译器会将某些辅助方法插入到类本身中,并在遇到一个时将它作为伴侣。令人惊讶的是,Big Two是apply,它创建了具有语法Foo(...)的对象及其邪恶的双unapply,它分解了对象以进行模式匹配。编译器只为主构造函数生成apply方法,并且它具有完全相同的签名。

所以看起来我们不能只使用构造函数做任何事情,所以让我们继续以某种方式自动将apply方法放入伴随对象中。一种方法是使用宏,但这对此来说太复杂了。另一种方式,我们定义一个混合到伴随对象的特征需要反射并且也会很复杂,并且每个类需要两行,一行用于class,一行用于{{1 }}。那么现在呢?

输入默认参数!事实上,这实际上是默认参数的教科书案例。 (抱歉在丛林周围殴打。)定义基类object

Animal

现在,对于每个派生类,在构造函数中,使用默认参数。默认参数的格式为abstract class Animal(name: String, color: String, age: Int) ,或者基本上是一个标有“等于某事”的正常参数。此处的默认设置似乎为$arg: $type = $defaultcolor = ""

age = 0

现在,表达式case class Rabbit(name: String, color: String = "", age: Int = 0) extends Animal(name, color, age) 将被翻译为new Rabbit("Fooey", "white")。 (不是真的,但足够接近。)对于new Rabbit("Fooey", "white", 0)方法也是如此。但请注意,这并不能完全定义“示例”的功能。可以定义apply而不定义age,如下所示:colorRabbit("Pit", age = 2)设置为age,默认2为{{1} }}

TL; DR 默认参数