【问题标题】:How to make manifest available for a generic type in scala?如何使清单可用于 scala 中的泛型类型?
【发布时间】:2018-04-19 10:01:22
【问题描述】:

鉴于通过 json4s 解析的 scala http 客户端,我有以下工作代码将 HttpResponse 的 Future 转换为案例类的 Future:

  def getJobIds(): Future[Seq[Job]] = {
    ... 
    var req = HttpRequest(
      method = HttpMethods.GET,
      uri = uri
    )

    val res: Future[HttpResponse] = Http().singleRequest(req)

    res.flatMap {
      case response@HttpResponse(StatusCodes.OK, _, _, _) => {
        val buffer = ByteString("")

        response.entity.dataBytes
          .runFold(buffer)(_ ++ _)
          .map(_.utf8String)
          .map(
            (body: String) => {
              parse(body).as[Seq[Job]]
            }
          )
      }
      case _: Any => throw new Throwable("Error!")
    }
  }

现在我想提取逻辑以使用泛型将 HttpResponse 转换为案例类,以免在其他调用中重复自己:

  def getJobIds(): Future[Seq[Job]] = {
    ...
    val res: Future[HttpResponse] = Http().singleRequest(req)
    transformResponse[Seq[Job]](res)
  }

  private def transformResponse[T](r: Future[HttpResponse]): Future[T] = {
    r.flatMap {
      case response@HttpResponse(StatusCodes.OK, _, _, _) => {
        val buffer = ByteString("")

        response.entity.dataBytes
          .runFold(buffer)(_ ++ _)
          .map(_.utf8String)
          .map(parse(_).extract[T])
      }
      case _: Any => throw new Throwable("Error!")
    }
  }

然而现在抛出:

 Metronome.scala:46:32: No Manifest available for T

换行

.map(parse(_).extract[T])

如何使用泛型使代码工作?

【问题讨论】:

    标签: scala generics generic-programming json4s


    【解决方案1】:

    问题来自于 json4s extract 方法。

    如果你查一下你会发现它的定义是:

      def extract[A](implicit formats: Formats, mf: scala.reflect.Manifest[A]): A =
        Extraction.extract(jv)(formats, mf)
    

    由于某种原因,隐式 Manifest 查找适用于具体类型,但对于一般情况,您必须为 T 类型定义隐式清单:

      private def transformResponse[T](r: Future[HttpResponse])
                                      (implicit ev: scala.reflect.Manifest[T]): Future[T] = {
        r.flatMap {
          case response@HttpResponse(StatusCodes.OK, _, _, _) => {
            val buffer = ByteString("")
    
            response.entity.dataBytes
              .runFold(buffer)(_ ++ _)
              .map(_.utf8String)
              .map(parse(_).extract[T])
          }
          case _: Any => throw new Throwable("Error!")
        }
    

    现在您的代码将编译并运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 2020-09-10
      • 1970-01-01
      • 2013-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多