如何创建一个 Either[S,T],其中 S 或 T 可以是 Unit?
How to create an Either[S,T] where S or T could be Unit?
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
的两边。这并不难,但我遇到的麻烦是创建一个没有值的 Left
或 Right
。在这种情况下,body 应该被完全消耗并丢弃。我尝试使用 ClassTag
s,但编译器认为类型是 Any
,而不是 S
或 T
。此方法的示例调用看起来像 responseValidationFlow[String, Unit]
生成 Source[Either[String, Unit]]
我相信,您可以在范围内为 Unit
定义一个隐式解组器:
implicit val unitUnmarshaller: FromByteStringUnmarshaller[Unit] =
Unmarshaller.strict(_ => ())
根据@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
.
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
的两边。这并不难,但我遇到的麻烦是创建一个没有值的 Left
或 Right
。在这种情况下,body 应该被完全消耗并丢弃。我尝试使用 ClassTag
s,但编译器认为类型是 Any
,而不是 S
或 T
。此方法的示例调用看起来像 responseValidationFlow[String, Unit]
生成 Source[Either[String, Unit]]
我相信,您可以在范围内为 Unit
定义一个隐式解组器:
implicit val unitUnmarshaller: FromByteStringUnmarshaller[Unit] =
Unmarshaller.strict(_ => ())
根据@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
.