如何覆盖具有相同基类的类的类型成员?

时间:2017-03-07 15:03:04

标签: scala oop generics type-members

很抱歉这个令人困惑的标题。

我正在尝试编写一些RequestResponse类来进行验证和解析。我想在编译时对类型有一些保证,但仍然有运行时多态性。我有以下基类:

abstract class Response()

abstract class Request() {
  type ResponseType = Response
  def ResponseClass: Class[_ <: ResponseType] = classOf[ResponseType]
}

所以,如果我有一个_ <: Request类型的实例,我可以用正确的类型解析,例如JSON响应:Json.parse(responseString).as[request.ResponseType]

我发现当我扩展这些课程时,我无法override ResponseType

case class AddedFooResponse() extends Response

case class AddFooRequest() extends Request {
  override type ResponseType = AddedFooResponse
}
  

错误:在类ResponseType中覆盖类型Request,等于this.Response;    类型ResponseType具有不兼容的类型     override type ResponseType = AddedFooResponse

我不确定为什么类型不兼容。我目前的解决方法有点笨拙,这是绑定基类中的类型:

abstract class Response()

abstract class Request() {
  type ResponseType <: Response
  // cannot initialize because no concrete class
  def ResponseClass: Class[_ <: ResponseType] 
}

并简单地覆盖ResponseTypeResponseClass

case class AddedFooResponse() extends Response

case class AddFooRequest() extends Request {
  override type ResponseType = AddedFooResponse
  override def ResponseClass = classOf[ResponseType]
}

这需要很多(看似)不必要的样板来覆盖ResponseClass

我做错了什么?

2 个答案:

答案 0 :(得分:0)

我认为你可以通过不设置此类型的默认值来逃避:

abstract class RequestBase() {
  type ResponseType
  def ResponseClass: Class[_ <: ResponseType] = classOf[ResponseType]
}

type Request = RequestBase { type ResponseType = Response }

case class AddFooRequest() extends Request {
  override type ResponseType = AddedFooResponse
}

答案 1 :(得分:0)

我发现我可以完全放弃ResponseClass,只需设置ResponseType并根据ResponseType的任何用途返回的实例进行匹配,以免它错误地解析并抛出异常。

abstract class Response
abstract class Request[+ResponseType <: Response]

case class FooResponse() extends Response {
  def greet = println("woo hoo!")
}

case class FooRequest() extends Request[FooResponse] {
  type ResponseType = FooResponse
}

val req: FooRequest = new FooRequest()
// Erase the type by making it an Object.
val resp: Object = new FooResponse()

resp.asInstanceOf[req.ResponseType] match {
  case fooResp: FooResponse => fooResp.greet
  case _ => println("This isn't good...")
}