How to call a method over and over until it returns a `Future` containing` None`

For a method that returns Future

like this ...

def remove(id: String): Future[Option[User]] = Future {
  // removes and returns the user identified by `id`
}

      

... how can I call it over and over until it returns the Future

containing value None

?

EDIT

It might be worth mentioning that I don't need to collect results. I just need to call the method while it finds the user to delete. The idea would be to loop

stop when it remove

returns Future[None]

.

+1


source to share


3 answers


Someone commented earlier that it doesn't make sense.

The surprise for me was that there is no easy to lazy consumption of futures. Future.find

is like firstCompletedOf

and doesn't mean find first in traversable order

.

scala> import concurrent._, ExecutionContext.Implicits._
import concurrent._
import ExecutionContext.Implicits._

scala> import java.util.concurrent.atomic._
import java.util.concurrent.atomic._

scala> val count = new AtomicInteger(10)
count: java.util.concurrent.atomic.AtomicInteger = 10

scala> def f(s: String) = Future { if (count.decrementAndGet <= 0) None else Some(s) }
f: (s: String)scala.concurrent.Future[Option[String]]

scala> def g(ss: List[String]): Future[List[String]] = f("hello") flatMap { case None => Future.successful(ss) case Some(s) => g(s :: ss) }
g: (ss: List[String])scala.concurrent.Future[List[String]]

scala> g(Nil)
res0: scala.concurrent.Future[List[String]] = scala.concurrent.impl.Promise$DefaultPromise@65a15628

scala> .value
res1: Option[scala.util.Try[List[String]]] = Some(Success(List(hello, hello, hello, hello, hello, hello, hello, hello, hello)))

      

To illustrate the usefulness of not blocking:

scala> :pa
// Entering paste mode (ctrl-D to finish)

import scala.util._
import concurrent._, ExecutionContext.Implicits._
import java.util.concurrent.atomic._

class Work {
  val count = new AtomicInteger(10)
  def f(s: String) = Future {
    if (count.decrementAndGet <= 0) None else Some(s)
  } andThen {
    case Success(Some(x)) => Console println s"Calculated $x"
    case Success(None)    => Console println "Done."
    case _                => Console println "Failed."
  }
}

// Exiting paste mode, now interpreting.

import scala.util._
import concurrent._
import ExecutionContext.Implicits._
import java.util.concurrent.atomic._
defined class Work

      

Shows the version Stream

that will not evaluate the prefix until the consumption thread goes through the lock. Expects:



scala> val work = new Work
work: Work = Work@1b45c0e

scala> Stream continually work.f("hello") takeWhile { x => Await.result(x, duration.Duration.Inf).nonEmpty }
Calculated hello
res0: scala.collection.immutable.Stream[scala.concurrent.Future[Option[String]]] = Stream(scala.concurrent.impl.Promise$DefaultPromise@66629f63, ?)

scala> .toList
Calculated hello
Calculated hello
Calculated hello
Calculated hello
Calculated hello
Calculated hello
Calculated hello
Calculated hello
Done.
res1: List[scala.concurrent.Future[Option[String]]] = List(scala.concurrent.impl.Promise$DefaultPromise@66629f63, scala.concurrent.impl.Promise$DefaultPromise@610db97e, scala.concurrent.impl.Promise$DefaultPromise@6f0628de, scala.concurrent.impl.Promise$DefaultPromise@3fabf088, scala.concurrent.impl.Promise$DefaultPromise@1e392345, scala.concurrent.impl.Promise$DefaultPromise@12f3afb5, scala.concurrent.impl.Promise$DefaultPromise@4ced35ed, scala.concurrent.impl.Promise$DefaultPromise@2c22a348, scala.concurrent.impl.Promise$DefaultPromise@7bd69e82)

scala> .foreach (Console println _.value.get)
Success(Some(hello))
Success(Some(hello))
[snip]

      

A different behavior is perhaps more desirable when you get a future that contains the result of evaluating a prefix:

scala> :pa
// Entering paste mode (ctrl-D to finish)

  val work = new Work
  def g(ss: List[String]): Future[List[String]] = work.f("hello") flatMap {
    case None => Future.successful(ss)
    case Some(s) => g(s :: ss)
  }

// Exiting paste mode, now interpreting.

work: Work = Work@796d3c9f
g: (ss: List[String])scala.concurrent.Future[List[String]]

scala> g(Nil)
Calculated hello
Calculated hello
res3: scala.concurrent.Future[List[String]] = scala.concurrent.impl.Promise$DefaultPromise@99a78d7
Calculated hello
Calculated hello
Calculated hello

scala> Calculated hello
Calculated hello
Calculated hello
Calculated hello
Done.

      

Use the future:

scala> .value
res5: Option[scala.util.Try[List[String]]] = Some(Success(List(hello, hello, hello, hello, hello, hello, hello, hello, hello)))

      

+4


source


Stream#continually

to do the same endlessly, and Stream#takeWhile

to stop it at a certain point. http://www.scala-lang.org/api/2.11.0/index.html#scala.collection.immutable.Stream



Stream.continually(/*remove*/).takeWhile(/*not Future[None]*/)

      

0


source


Here he is:

import concurrent._, ExecutionContext.Implicits._
import java.util.concurrent.atomic._

val count = new AtomicInteger(10)

def f(s: String) = Future {
  if (count.decrementAndGet <= 0) None else Some(s)
}

Iterator continually {
  f("hello")
} takeWhile {
  Await.result(_, duration.Duration.Inf).nonEmpty
} foreach { _.map { _.map {
  println
}}

      

Hope this helps.

0


source







All Articles