arn*_*off 0 scala covariance existential-type akka playframework
我有一个构建在Play / Lagom堆栈之上的应用程序。我需要调用一项服务,该服务需要Source[T, NotUsed]将文件流式传输到该服务。这是服务的接口:
def foo(fooId: UUID): ServiceCall[Source[ByteString, NotUsed], Source[String, NotUsed]]
Run Code Online (Sandbox Code Playgroud)
因此,我通过Accumulator.source以下方式从Play文档中使用:
private def doSomething(fooId: UUID): BodyParser[Future[Seq[String]]] = BodyParser { _ =>
Accumulator.source[ByteString]
.mapFuture { source: Source[ByteString, NotUsed] =>
externalService
.foo(fooId)
.invoke(source)
.map { x =>
Right(x.runWith(Sink.seq[String]))
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在mapFuture调用中,source的类型为Source[ByteString, _],但是如果Source[ByteString, NotUsed]如上例所示,将其更改为以便调用服务,则在IDE中出现Source[ByteString, _]预期的错误
。难道不_意味着我可以将类型更改为想要的任何类型,包括NotUsed吗?另一方面,这两者在语义上是否应该等效吗?我发现,在某些以前的版本中,当实例化值无关紧要时,引入Akka团队akka.NotUsed来进行替换Unit,但这仍然无法为我提供解决问题的线索。
上面的代码段类似于Play文档中有关将身体指向其他位置的示例。
另一方面,这两者在语义上是否应该等效吗?
不能。它们不是等效的,因为一个是另一个的子类型,反之亦然。
Source[ByteString, NotUsed]是的子类型Source[ByteString, _]。并且因为Source是协变Source[ByteString, _]的Source[ByteString, Any]。
implicitly[Source[ByteString, NotUsed] <:< Source[ByteString, _]]
implicitly[Source[ByteString, _] =:= Source[ByteString, Any]]
implicitly[Source[ByteString, Any] =:= Source[ByteString, _]]
Run Code Online (Sandbox Code Playgroud)
Accumulator.source[ByteString] 具有类型 Accumulator[ByteString, Source[ByteString, _]]。.mapFuture(..) 接受 Source[ByteString, _] => Future[B]。并且由于X => Y协变而Y相反X Source[ByteString, _] => Future[B]是的子类型Source[ByteString, NotUsed] => Future[B])
implicitly[(Source[ByteString, _] => Future[B]) <:< (Source[ByteString, NotUsed] => Future[B])]
Run Code Online (Sandbox Code Playgroud)
因此,您可以使用Source[ByteString, _] => Future[B]代替,Source[ByteString, NotUsed] => Future[B]反之亦然。
(B似乎是Future[Either[Result, Future[Seq[String]]]]。)
https://docs.scala-lang.org/tour/variances.html