为什么 Future[Set[Unit]] 不被接受为 Future[Unit]?
Why is Future[Set[Unit]] not accepted as Future[Unit]?
使用 futures 时的一个常见问题是,当您期望 Future[Unit]
时,甚至 Future[Future[Unit]]
也会被接受(参见 Why Shouldn’t You Use Future[Unit] as a Return Type in a Scala Program)。
我最近很惊讶Future.sequence(setOfFutures)
在这种情况下不被接受:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val set = Set(Future(()))
def fuu: Future[Unit] = {
Future.sequence(set)
}
使用 Scala 2.12.13 我得到错误:
type mismatch;
found : scala.concurrent.Future[scala.collection.immutable.Set[Unit]]
使用 Scala 2.13 我得到:
Cannot construct a collection of type Unit with elements of type Unit based on a collection of type scala.collection.immutable.Set[scala.concurrent.Future[Unit]].
当我将函数体更改为:
val s = Future.sequence(set)
s
我设置了和以前一样的错误。
为什么 Future[Future[Unit]]
被接受为 Future[Unit]
而 Future[Set[Unit]]
或 Future[List[Unit]]
不被接受?
考虑 Scala 2.13
中 Future.sequence
的签名
def sequence[A, CC[X] <: IterableOnce[X], To](in: CC[Future[A]])(
implicit
bf: BuildFrom[CC[Future[A]], A, To],
executor: ExecutionContext
): Future[To]
如此给予
val set = Set(Future(()))
def fuu: Future[Unit] = Future.sequence(set)
然后推理将分配 sequence
的类型参数,就像这样
To = Unit
A = Unit
CC = Set
例如考虑 fuu
的 return 类型 Future[Unit] = Future[To]
。因此我们有
def fuu: Future[Unit] = Future.sequence[Unit, Set, Unit](set)
所以编译器需要隐式分配bf
参数
scala> implicitly[BuildFrom[Set[Future[Unit]], Unit, Unit]]
^
error: Cannot construct a collection of type Unit with elements of type Unit based on a collection of type Set[scala.concurrent.Future[Unit]].
现在考虑 Future.sequence
的 Scala 2.12 签名
def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(
implicit
cbf: CanBuildFrom[M[Future[A]],A,M[A]],
executor: ExecutionContext
): Future[M[A]]
如此给予
val set = Set(Future(()))
def fuu: Future[Unit] = Future.sequence(set)
推断变为
A = Unit
M = Set
所以我们有
def fuu: Future[Unit] = Future.sequence[Unit, Set](set)
其中编译器可以成功地隐式分配 cbf
参数
scala> implicitly[CanBuildFrom[Set[Future[Unit]],Unit,Set[Unit]]]
res4: scala.collection.generic.CanBuildFrom[Set[scala.concurrent.Future[Unit]],Unit,Set[Unit]] = scala.collection.generic.GenSetFactory$$anon@1bff70a6
因此我们在 2.12 中实际上有以下情况
scala> def fuu: Future[Unit] = Future.sequence(set) : Future[Set[Unit]]
<console>:25: error: type mismatch;
found : scala.concurrent.Future[Set[Unit]]
required: scala.concurrent.Future[Unit]
def fuu: Future[Unit] = Future.sequence(set) : Future[Set[Unit]]
这应该可以解释两个 Scala 版本之间的两个编译器错误消息之间的区别与值丢弃无关,而是与推理如何分配相应类型有关。
使用 futures 时的一个常见问题是,当您期望 Future[Unit]
时,甚至 Future[Future[Unit]]
也会被接受(参见 Why Shouldn’t You Use Future[Unit] as a Return Type in a Scala Program)。
我最近很惊讶Future.sequence(setOfFutures)
在这种情况下不被接受:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val set = Set(Future(()))
def fuu: Future[Unit] = {
Future.sequence(set)
}
使用 Scala 2.12.13 我得到错误:
type mismatch;
found : scala.concurrent.Future[scala.collection.immutable.Set[Unit]]
使用 Scala 2.13 我得到:
Cannot construct a collection of type Unit with elements of type Unit based on a collection of type scala.collection.immutable.Set[scala.concurrent.Future[Unit]].
当我将函数体更改为:
val s = Future.sequence(set)
s
我设置了和以前一样的错误。
为什么 Future[Future[Unit]]
被接受为 Future[Unit]
而 Future[Set[Unit]]
或 Future[List[Unit]]
不被接受?
考虑 Scala 2.13
中Future.sequence
的签名
def sequence[A, CC[X] <: IterableOnce[X], To](in: CC[Future[A]])(
implicit
bf: BuildFrom[CC[Future[A]], A, To],
executor: ExecutionContext
): Future[To]
如此给予
val set = Set(Future(()))
def fuu: Future[Unit] = Future.sequence(set)
然后推理将分配 sequence
的类型参数,就像这样
To = Unit
A = Unit
CC = Set
例如考虑 fuu
的 return 类型 Future[Unit] = Future[To]
。因此我们有
def fuu: Future[Unit] = Future.sequence[Unit, Set, Unit](set)
所以编译器需要隐式分配bf
参数
scala> implicitly[BuildFrom[Set[Future[Unit]], Unit, Unit]]
^
error: Cannot construct a collection of type Unit with elements of type Unit based on a collection of type Set[scala.concurrent.Future[Unit]].
现在考虑 Future.sequence
def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(
implicit
cbf: CanBuildFrom[M[Future[A]],A,M[A]],
executor: ExecutionContext
): Future[M[A]]
如此给予
val set = Set(Future(()))
def fuu: Future[Unit] = Future.sequence(set)
推断变为
A = Unit
M = Set
所以我们有
def fuu: Future[Unit] = Future.sequence[Unit, Set](set)
其中编译器可以成功地隐式分配 cbf
参数
scala> implicitly[CanBuildFrom[Set[Future[Unit]],Unit,Set[Unit]]]
res4: scala.collection.generic.CanBuildFrom[Set[scala.concurrent.Future[Unit]],Unit,Set[Unit]] = scala.collection.generic.GenSetFactory$$anon@1bff70a6
因此我们在 2.12 中实际上有以下情况
scala> def fuu: Future[Unit] = Future.sequence(set) : Future[Set[Unit]]
<console>:25: error: type mismatch;
found : scala.concurrent.Future[Set[Unit]]
required: scala.concurrent.Future[Unit]
def fuu: Future[Unit] = Future.sequence(set) : Future[Set[Unit]]
这应该可以解释两个 Scala 版本之间的两个编译器错误消息之间的区别与值丢弃无关,而是与推理如何分配相应类型有关。