2017-03-07 62 views
1

对不起,标题很混乱。如何覆盖具有相同基类的类的类型成员?

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

abstract class Response() 

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

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

我发现,当我向这些类,我无法overrideResponseType

case class AddedFooResponse() extends Response 

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

error: overriding type ResponseType in class Request , which equals this.Response ; type ResponseType has incompatible type 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不必要的样板。

我在做什么不正确?

+0

为什么你需要以这种方式存储'ResponseType'类?我觉得可能有更好的方法来实现你不需要'java.lang.Class'的东西。 –

+0

@MichaelZajac我有一个验证器,比较'ResponseClass'和接收到的'Response'的类。如果我有响应类型,它可能会变得没有意义。如果没有别的,这个问题很有趣。充其量是最实用的。如果您有兴趣,请参阅[这里](http://ideone.com/z4cC8C)。 – erip

+0

我会说,使用'类型ResponseType <:Response'是一个正确的方向,但使用'classOf'并不能很好地工作,这就是为什么它需要退出抽象类。否则,你有一个不变的类型成员。 –

回答

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 
} 
0

我发现,我可以根据返回的情况下简单地设置ResponseType和匹配完全ResponseClass放弃一切使用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...") 
} 
相关问题