【问题标题】:How can I override a type member of a class with the same base class?如何覆盖具有相同基类的类的类型成员?
【发布时间】:2017-03-07 15:03:03
【问题描述】:

对不起,令人困惑的标题。

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

abstract class Response()

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

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

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

case class AddedFooResponse() extends Response

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

错误:覆盖类Request中的类型ResponseType,等于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

我做错了什么?

【问题讨论】:

  • 为什么要这样存储ResponseType的类呢?我觉得可能有更好的方法来实现您所需要的,而不需要 java.lang.Class
  • @MichaelZajac 我有一个验证器,它将ResponseClass 与收到的Response 的类进行比较。如果我有响应类型,它可能会变得没有意义。如果不出意外,这个问题很有趣。充其量是实用的。如果您有兴趣,请参阅here
  • 我会说使用type ResponseType &lt;: Response是朝着正确方向迈出的一步,但是使用classOf并不能很好地工作,这就是为什么它需要退出摘要班级。否则你有一个不变的类型成员。
  • @MichaelZajac 那么你知道我如何能够实现request.ResponseType == typeOf[response] 这样的目标吗?也许这就是问题的症结所在。

标签: scala oop generics type-members


【解决方案1】:

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

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
}

【讨论】:

    【解决方案2】:

    我发现我可以完全放弃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...")
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-02
      • 2012-02-16
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 2019-12-06
      • 2011-09-15
      • 1970-01-01
      相关资源
      最近更新 更多