1

有没有办法让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.。所以它说它不能序列化 type 的对象A,这是有道理的。然而,目标是让thisinJson.toJson(this)引用子类(在本例中是B)。

有没有办法做到这一点?如果没有,有没有其他方法可以Json.toJson(...)在超类中实现该方法而不必在子类(以及所有其他子类A)中实现?

4

1 回答 1

4

从父类引用当前子类的常用技巧是使用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)
}

或者使用上下文绑定表示法:

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

而且由于这个 F-bounded polymorphism 只是一个实现细节,并且总是引用泛型A,因为A[_]它是非常样板的,所以您可以将此代码移动到中间的abstract class.

所以一个完整的例子看起来像这样:

abstract class A() {
  def toJson: JsValue
}

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

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

val a: A = B("foo")
println(a.toJson)
于 2016-02-26T10:00:17.097 回答