Source [T,_]和Source [T,NotUsed]有什么区别?

时间:2019-09-13 12:37:13

标签: scala playframework akka covariance existential-type

我有一个构建在Play / Lagom堆栈之上的应用程序。我需要调用一个需要Source[T, NotUsed]才能将文件流式传输到它的服务。这是服务的接口:

def foo(fooId: UUID): ServiceCall[Source[ByteString, NotUsed], Source[String, NotUsed]]

因此,我通过以下方式使用Play文档中的Accumulator.source

  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]))
          }
      }
  }

现在,在mapFuture调用中,source的类型为Source[ByteString, _],但是如果我将其更改为Source[ByteString, NotUsed]以便调用服务,如上面的示例,我在IDE中遇到了一个错误 应该是Source[ByteString, _]_是否应该意味着我可以将类型更改为想要的任何类型,包括NotUsed?另一方面,这两者在语义上是否应该等效吗?我发现,当在某些以前的版本中物化值无关紧要时,Akka团队引入了akka.NotUsed来代替Unit,但这仍然没有为我提供解决问题的线索。

上面的代码段与Play documentation on directing the body elsewhere.

中的示例相似

1 个答案:

答案 0 :(得分:7)

  

另一方面,这两者在语义上不应该等效吗?   反正?

不。它们不是等效的,因为一个是另一个的子类型,反之亦然。

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, _]]

Accumulator.source[ByteString] has type Accumulator[ByteString, Source[ByteString, _]].mapFuture(..) accepts Source[ByteString, _] => Future[B]。并且由于X => YY中是协变的,但在X中是协变的,因此Source[ByteString, _] => Future[B]Source[ByteString, NotUsed] => Future[B])的子类型

implicitly[(Source[ByteString, _] => Future[B]) <:< (Source[ByteString, NotUsed] => Future[B])]

因此,您可以使用Source[ByteString, _] => Future[B]代替Source[ByteString, NotUsed] => Future[B],反之亦然。

({B似乎是Future[Either[Result, Future[Seq[String]]]]。)

https://docs.scala-lang.org/tour/variances.html