Почему Будущее[Набор[Единица]] не принимается как Будущее[Единица]?

#scala #types #type-conversion

Вопрос:

Распространенная ошибка при работе с фьючерсами заключается в том , что, когда вы ожидаете Future[Unit] , даже Future[Future[Unit]] будет принято (см., Например, Почему Вы не должны использовать Future[Unit] в качестве типа возврата в программе Scala).

Я был удивлен, что в последнее 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 я получаю ошибку:

несоответствие типов;

найдено : scala.одновременно.Будущее[scala.коллекция.неизменяемая.Набор[Единица измерения]]

С помощью Scala 2.13 я получаю:

Невозможно создать коллекцию единиц типа с элементами единицы типа на основе коллекции типа scala.collection.immutable.Установите[scala.одновременный.Будущее[Единица измерения]].

Когда я изменяю тело функции на:

   val s = Future.sequence(set)
  s
 

Я получаю ту же ошибку, что и раньше.

Почему Future[Future[Unit]] принимается как Future[Unit] и Future[Set[Unit]] или Future[List[Unit]] нет?

Ответ №1:

Рассмотрим подпись Future.sequence в Scala 2.13

 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 тип возвращаемого 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]].
 

Теперь рассмотрим Scala 2.12 подпись 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$1@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, связанную не с отбрасыванием значений, а с тем, как вывод назначил соответствующие типы.

Комментарии:

1. Теперь я понимаю. Предпосылка моего вопроса неверна: Future[Future[Unit]] не принимается как Future[Unit] . Вместо Future(Future(())) этого он переписывается как Future(Future(()), ()) , когда определяется, где Future[Unit] ожидается.

2. Примечание: похоже, что значение, исключающее перезапись, изменилось в Scala 3, так как при этом код def foo: Future[Unit] = Future(Future(())) больше не принимается и выдает найденную ошибку: scala.concurrent. Требуется будущая[Единица измерения]: Единица измерения.

3. Я нашел ответ неудовлетворительным, потому что не видел движущихся частей. Он терпит неудачу, потому что у него нет строителя BuildFrom[Set[Future[Unit]], Unit, Unit] . Я могу это реализовать. Может быть, он запускает все в специальном контексте в качестве побочного эффекта. Я понимаю, что ОП спрашивает, почему каким-то образом не срабатывает отбрасывание ценности.