在Scala中,请参阅抽象超类中的子类

时间:2016-02-26 09:26:20

标签: scala inheritance implicit play-json

超类中的this关键字是否有办法引用该类的子类?具体来说,我正在尝试执行以下操作(Json指的是Play的Json库):

abstract class A() {
  def toJson[T](implicit writes: Writes[T]): JsValue = Json.toJson(this)
}

case class B(myProperty: String) extends A
object B { implicit val bFormat = Json.format[B] }

这会产生错误No Json serializer found for type A. Try to implement an implicit Writes or Format for this type.。所以它说它不能序列化A类型的对象,这是有道理的。但是,目标是this中的Json.toJson(this)引用子类(在本例中为B)。

有没有办法实现这个目标?如果没有,有没有其他方法可以在超类中实现Json.toJson(...)方法而不必在子类(以及A的所有其他子类)中实现?

1 个答案:

答案 0 :(得分:3)

从父级引用当前子类的常用技巧是使用F-bounded polymorphism

// Here `T` refers to the type of the current subclass
abstract class A[T <: A[T]]() { 
  this: T =>
  def toJson(implicit writes: Writes[T]): JsValue = Json.toJson(this)
}

// We have to specify the current subclass in `extends A[B]`
case class B(myProperty: String) extends A[B]
object B { implicit val bFormat = Json.format[B] }

println(B("foo").toJson)

这不允许您为任何通用toJson拨打A但是:

val a: A[_] = B("foo")
println(a.toJson)      // Doesn't compile with: 
                       //   No Json serializer found for type _$1. 
                       //   Try to implement an implicit Writes or Format for this type.

要解决此问题,您必须在创建对象时为子类型保存Writes

abstract class A[T <: A[T]](implicit writes: Writes[T]) { 
  this: T =>
  def toJson: JsValue = Json.toJson(this)
}

或者使用context bound表示法:

abstract class A[T <: A[T] : Writes] { 
  this: T =>
  def toJson: JsValue = Json.toJson(this)
}

由于这个F-bounded多态性事物只是一个实现细节,并且总是引用泛型A,因为A[_]非常模板化,你可以将这段代码移到一个中间{{1 }}

所以一个完整的例子如下:

abstract class