【问题标题】:Improvement of generic arguments with reflection用反射改进泛型参数
【发布时间】:2013-07-06 17:20:17
【问题描述】:

这是我目前正在开发的 Http-Client 的简化版:

class Request[A]( val url: String, val event: Callbacks[A] )
{
    def run: Try[A] = ...
}
case class Image( override val url: String, override val event: Callbacks[Bitmap] ) extends Request[Bitmap]

object GET
{
    def apply[A <: Request[B] : ClassTag, B : ClassTag]( url: String, event: Callbacks[B] ): Try[B] =
    {
        classOf[A]
            .runtimeClass
            .getConstructor( classOf[String], classOf[Callbacks[B]] )
            .newInstance( url, event )
            .asInstanceOf[A]
            .run
    }
}

object Main extends App
{
    GET[Image, Bitmap]( "http://...", null )
}

我想改进我的 API,使我可以像这样调用 GET

GET[Image]( "http://...", null )

提供通用参数Image 应该意味着我正在使用Bitmap,因此我不想再次指定它。

【问题讨论】:

    标签: scala generics reflection


    【解决方案1】:

    您可以使用类似于CanBuildFrom 的模式:使用隐式构建器来创建合适的Request

    一些类型:

    abstract class Content
    
    class Bitmap extends Content
    
    class Callbacks[T]
    
    abstract class Request[C <: Content](val url: String, val event: Callbacks[C]) {
      def run: C
    }
    
    class ImageRequest(_url: String, _event: Callbacks[Bitmap]) 
      extends Request[Bitmap](_url, _event) {
    
      def run: Bitmap = {
        new Bitmap()
      }
    }
    

    现在是隐式参数RequestBuilder的类型:

    abstract class RequestBuilder[C <: Content] {
      def create(url: String, event: Callbacks[C]): Request[C]
    }
    
    class ImageRequestBuilder extends RequestBuilder[Bitmap]() {
      def create(url: String, event: Callbacks[Bitmap]): ImageRequest = {
        new ImageRequest(url, event)
      }
    }
    
    object ImplicitContainer {
      implicit val ImplicitImageRequestBuilder = new ImageRequestBuilder()
    }
    

    这样使用:

    object GET {
      def apply[C <: Content](url: String, event: Callbacks[C])
                             (implicit rb: RequestBuilder[C]): C = {
        rb.create(url, event).run
      }
    }
    
    object HttpClient extends App {
      import ImplicitContainer._
    
      val bitmap = GET[Bitmap]("http://...", null)
      println(bitmap)
    }
    

    这样,当您致电GET 时,您总是会收到不同的请求

    【讨论】:

      【解决方案2】:

      我能得到的最接近的方法是提供一个隐式参数并将我的所有结果映射器(图像、Html、...)注册为隐式值。由于额外的隐式定义,这增加了一些配置开销,但产生了更好定制的优势。这样我也摆脱了反射部分。

      implicit val image = Image.apply _
      

      object GET
      {
          def apply[T]( url: String, event: Callbacks[T] )( implicit request: ( String, Callbacks[T] ) => Request[T] ): Try[T] =
          {
              request( url, event ).run
          }
      }
      

      import image
      
      GET[Bitmap]( "http://...", null )
      GET[Bitmap]( "http://...", null )( myOwnAwesomeImageProcessor _ )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-06-25
        • 1970-01-01
        • 1970-01-01
        • 2021-07-05
        • 1970-01-01
        • 2022-09-27
        • 1970-01-01
        相关资源
        最近更新 更多