在 Scala 中,引用 Abstract Super 中的子类 Class
In Scala, Refer to Subclass in Abstract Super Class
有没有办法让超级 class 中的 this
关键字引用那个 class 的子 class?具体来说,我正在尝试执行以下操作(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
类型的对象,这是有道理的。然而,目标是让 Json.toJson(this)
中的 this
引用子 class(在本例中,它是 B
)。
有什么办法可以做到这一点吗?如果没有,有没有其他方法可以在 superclass 中实现 Json.toJson(...)
方法,而不必在 subclass (以及所有其他 subclasses 中实现A
)?
从父类引用当前子类的常用技巧是使用 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)
这不允许您为任何通用 A
调用 toJson
:
val a: A[_] = B("foo")
println(a.toJson) // Doesn't compile with:
// No Json serializer found for type _.
// 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 有界多态性只是一个实现细节,并且总是引用通用 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)
有没有办法让超级 class 中的 this
关键字引用那个 class 的子 class?具体来说,我正在尝试执行以下操作(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
类型的对象,这是有道理的。然而,目标是让 Json.toJson(this)
中的 this
引用子 class(在本例中,它是 B
)。
有什么办法可以做到这一点吗?如果没有,有没有其他方法可以在 superclass 中实现 Json.toJson(...)
方法,而不必在 subclass (以及所有其他 subclasses 中实现A
)?
从父类引用当前子类的常用技巧是使用 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)
这不允许您为任何通用 A
调用 toJson
:
val a: A[_] = B("foo")
println(a.toJson) // Doesn't compile with:
// No Json serializer found for type _.
// 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 有界多态性只是一个实现细节,并且总是引用通用 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)