我会让代码发言:
import scala.concurrent.Future
trait SomeRequest
trait SomeResponse
trait ApiStandard {
def apiCall[Req <: SomeRequest, Resp <: SomeResponse](request: Req): Future[Resp]
}
case class XXRequest() extends SomeRequest
case class XXResponse() extends SomeResponse
class XXStandard extends ApiStandard {
override def apiCall(request: XXRequest): Future[XXResponse] = ???
}
基本上我有几个数据特征(SomeRequest,SomeResponse)和行为特征ApiStandard。还有案例类XXRequest和XXResponse覆盖数据特征。我正在尝试创建一个名为XXStandard的ApiStandard的具体实现。但它在语法上并不正确。作为斯卡拉初学者,我无法理解为什么。
请稍微说清楚。
感谢。
答案 0 :(得分:4)
ApiStandard定义了一种方法apiCall
,它接受的参数比XXStandard
提供的参数更灵活。
为了说明,
如果你有
val something: ApiStandard = ???
你知道你可以打电话
val req: SomeRequest
something(req)
如果???
可能是new XXStandard()
,XXStandard
只接受XXRequest
作为apiCall的参数,那么这将被破坏:没有办法知道req实际上是XXRequest
,事实上,它不一定是一个。
幸运的是,这不会编译,因为apiCall
中的XXStandard
无法实现ApiStandard.apiCall
。
要使XXStandard
成为可以作为ApiStandard子类型的东西,XXStandard中的apiCall必须采用您在特征中声明的类型,或者作为其参数的超类型。
TL; DR:
方法的参数类型是逆变的。
答案 1 :(得分:1)
您对apiCall
的定义表明它必须适用于任何Req <: SomeRequest
和Resp <: SomeResponse
,因此调用者可以像(例如)apiCall[MyReq, SomeoneElsesResp](new MyReq)
一样调用它。但XXStandard
中的实施并不像这样;它只支持单个请求和响应类型。假设你想要的是什么,你需要将类型参数移到ApiStandard
:
trait ApiStandard[Req <: SomeRequest, Resp <: SomeResponse] {
def apiCall(request: Req): Future[Resp]
}
class XXStandard extends ApiStandard[XXRequest, XXResponse] {
override def apiCall(request: XXRequest): Future[XXResponse] = ???
}