2016-07-06 20 views
13

Jak mogę przekonwertować Option[Future[T]] na Future[Option[T]] w scala?Opcja Scala [Przyszłość [T]] do przyszłości [Opcja [T]]

chcę go używać w:

val customerAddresses = for { 
    a <- addressDAO.insert(ca.address) // Future[Address] 
    ia <- ca.invoiceAddress.map(addressDAO.insert) // Option[Future[Address]] 
} yield (a, ia) // Invalid value have to be two futures 

Tutaj sygnatury metody insert

def insert(address: Address): Future[Address] 

ca jest CustomerData

case class CustomerData(address: Address, invoiceAddress: Option[Address]) 
+0

Więc 'a <- addressDAO.insert (ca.address)' zwraca 'Future [Option]'? –

+0

Czy możesz określić sygnatury swoich metod? –

+5

Użyłbym '.sequence' z' scalaz/cats' z https://github.com/milessabin/si2712fix-plugin - ale to prawdopodobnie byłaby przesada. – Reactormonk

Odpowiedz

18
import scala.concurrent.Future 
import scala.concurrent.ExecutionContext 

def f[A](x: Option[Future[A]])(implicit ec: ExecutionContext): Future[Option[A]] = 
    x match { 
    case Some(f) => f.map(Some(_)) 
    case None => Future.successful(None) 
    } 

Przykłady:

scala> f[Int](Some(Future.successful(42))) 
res3: scala.concurrent.Future[Option[Int]] = Success(Some(42)) 

scala> f[Int](None) 
res4: scala.concurrent.Future[Option[Int]] = [email protected] 
3

Standardowa biblioteka udostępnia metody wykorzystania Future.sequence w opcji, niestety trzeba je połączyć razem.

Albo jako szybki sposób:

def swap[M](x: Option[Future[M]]): Future[Option[M]] = 
    Future.sequence(Option.option2Iterable(x)).map(_.headOption) 

Uwaga znalazłem ukryte Option.option2Iterable był już w zasięgu dla mnie. Więc może nie trzeba, aby zapewnić go, zmniejszając kod do Future.sequence(x).map(_.headOption)

Albo może wolisz metodę rozszerzenia:

implicit class OptionSwitch[A](f: Option[Future[A]]) { 
    import scala.concurrent.Future 

    def switch: Future[Option[A]] = Future.sequence(Option.option2Iterable(f)) 
     .map(_.headOption) 
    } 


val myOpt = Option(Future(3)) 
myOpt.switch 
2

Oto inne rozwiązanie:

def swap[T](o: Option[Future[T]]): Future[Option[T]] = 
    o.map(_.map(Some(_))).getOrElse(Future.successful(None)) 

Sztuką jest przekonwertować Option[Future[T]] na Option[Future[Option[T]]] co jest łatwe, a następnie wyodrębnić wartość z tego Option.

Powiązane problemy