在第三方库中,有一系列请求类,它们均来自某个通用基类,该通用基类是通用的,并且将响应类作为参数:
abstract class AbstractRequest[ResponseType] {
…
def execute(): ResponseType
}
class UserList {…}
class UserListRequest extends AbstractRequest[UserList] {…}
class Avatar {…}
class AvatarRequest extends AbstractRequest[Avatar] {…}
…
我想编写一些接受请求实例的通用方法,以某些特殊方式执行几次,并将响应的处理委托给参数中提供的函数:
def specialMultiExecute(request: Req)(responseHandler: Resp => Unit): Unit = …
—被称为:
val myRequest: UserListRequest = …
specialMultiExecute(myRequest){ userList => … }
问题是我需要以某种方式在Req
声明中指定Resp
和specialMultiExecute
类型。我尝试了明显的方法:
def specialMultiExecute[Req <: AbstractRequest[Resp], Resp](request: Req)(responseHandler: Resp => Unit): Unit = …
-但是Scala编译器无法推导通用参数类型(需要使用specialMultiExecute
[UserListRequest, UserList]
(myRequest){ userList => … }
这样的显式规范)。
在这种情况下,我可以在C ++中用单个模板参数Req
编写模板函数,同时使Resp
被确定为方法Req::execute
的结果类型< / em>:
template<typename Req>
void specialMultiExecute(
Req request,
std::function<void (decltype(std::declval<Req>().execute()))> responseHandler
) {…}
//i.e. we use `decltype(std::declval<Req>().execute())` instead of Resp
是否可以编写类似Scala的东西?
我的意思是(用类似于Scala的伪代码):
def specialMultiExecute[Req <: AbstractRequest](request: Req)(responseHandler: ResultTypeOf(Req#execute) => Unit): Unit = …
答案 0 :(得分:3)
这是类型推断机制的限制。
解决此问题的最简单方法是使用隐式证据,即Req
是AbstractRequest[ResponseType]
的子类型。
这里是一个例子。
import scala.language.implicitConversions
import scala.reflect.runtime.universe.TypeTag
abstract class AbstractRequest[ResponseType] {
def execute(): ResponseType
}
final case class User(id: Int, name: String)
final case class House(id: Int, price: Int)
class UserListRequest extends AbstractRequest[List[User]] {
override def execute(): List[User] = List(User(id = 3, name = "Sasha"))
override def toString: String = "UserListRequest"
}
final class RequestWrapper[Req, Resp](val request: Req) extends AnyVal {
type ResponseType = Resp
}
implicit def request2wrapper[Req, Resp](request: Req)(implicit ev: Req <:< AbstractRequest[Resp]): RequestWrapper[Req, Resp] =
new RequestWrapper(request)
def specialMultiExecute[Req, Resp](wrapper: RequestWrapper[Req, Resp])
(responseHandler: wrapper.ResponseType => Unit)
(implicit ev: Req <:< AbstractRequest[Resp], TTReq: TypeTag[Req], TTResp: TypeTag[Resp]): Unit = {
val request: Req = wrapper.request
val executionResult: Resp = request.execute()
responseHandler(executionResult)
println(TTReq)
println(TTResp)
println(request)
}
specialMultiExecute(new UserListRequest())(println)
// List(User(3,Sasha))
// TypeTag[UserListRequest]
// TypeTag[List[User]]
// UserListRequest
修改了上面的代码示例,以允许识别所使用的具体Request
和Response
类型。