代码之家  ›  专栏  ›  技术社区  ›  Sasha

Scala:确定泛型中使用的方法结果类型

  •  4
  • Sasha  · 技术社区  · 7 年前

    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 = …
    

    特殊多重执行 [UserListRequest, UserList] (myRequest){ userList => … } 是必需的)。

    请求 ,在制作 响应 确定为 Req::execute :

    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的东西?

    def specialMultiExecute[Req <: AbstractRequest](request: Req)(responseHandler: ResultTypeOf(Req#execute) => Unit): Unit = …
    1 回复  |  直到 7 年前
        1
  •  3
  •   Luis Miguel Mejía Suárez    7 年前

    这是类型推断机制的一个限制。 解决这个问题的最简单方法是使用 隐含证据 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
    

    Reference <:< . Reference 对于 .

    编辑

    对上述代码示例进行了修改,以便识别混凝土 Request Response 正在使用的类型。