如何创建一个[S,T],其中S或T可以是单位?

时间:2017-12-13 17:41:51

标签: scala akka akka-stream akka-http

private def responseValidationFlow[T](responsePair: ResponsePair)(implicit evidence: FromByteStringUnmarshaller[T]) = responsePair match {
    case (Success(response), _) => {
      response.entity.dataBytes
        .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 8192))
        .mapAsyncUnordered(Runtime.getRuntime.availableProcessors()) { body =>
          if (response.status == OK) {
            val obj: Future[T] = Unmarshal(body).to[T]
            obj.foreach(x => log.debug("Received {}: {}.", x.getClass.getSimpleName, x))
            obj.map(Right(_))
          } else {
            val reason = body.utf8String
            log.error("Non 200 response status: {}, body: {}.", response.status.intValue(), reason)
            Future.successful(reason)
              .map(Left(_))
          }
        }
    }
    case (Failure(t), _) => {
      Source.single(Left(t.getMessage))
    }
  }

我想做的是参数化Either的两边。这并不难,但我遇到的问题是创建一个没有值的LeftRight。在这种情况下,身体应该被完全消耗并丢弃。我尝试使用ClassTag,但编译器认为类型为Any,而不是ST。此方法的示例调用看起来像responseValidationFlow[String, Unit]生成Source[Either[String, Unit]]

2 个答案:

答案 0 :(得分:0)

我相信,你可以在范围内为Unit定义一个隐式的unmarshaller:

implicit val unitUnmarshaller: FromByteStringUnmarshaller[Unit] = 
  Unmarshaller.strict(_ => ())

答案 1 :(得分:0)

根据@Kolmar的建议,这是工作代码。

private def responseValidationFlow[L, R](responsePair: ResponsePair)(
  implicit ev1: FromByteStringUnmarshaller[L], ev2: FromByteStringUnmarshaller[R]
): Source[Either[L, R], Any] = {
  responsePair match {
    case (Success(response), _) => {
      response.entity.dataBytes
        .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 8192))
        .mapAsyncUnordered(Runtime.getRuntime.availableProcessors()) { body =>
          if (response.status == OK) {
            val obj: Future[R] = Unmarshal(body).to[R]
            obj.foreach(x => log.debug("Received {}.", x.getClass.getSimpleName))
            obj.map(Right(_))
          } else {
            log.error("Non 200 response status: {}.", response.status.intValue())
            Unmarshal(body).to[L]
              .map(Left(_))
          }
        }
    }
    case (Failure(t), _) => {
      log.error(t, "Request failed.")
      Source.empty
    }
  }
}

如果调用此方法responseValidationFlow[Status, Unit],则会在呼叫网站上提供FromByteStringUnmarshaller[Unit]。编译器使用implicit证据来查找所需的Unmarshaller