访问scala期货返回的价值

时间:2013-07-18 02:44:14

标签: scala future

我是scala期货的新手,我对scala期货的回报价值有疑问。

因此,scala未来的语法通常是

 def downloadPage(url: URL) = Future[List[Int]] {

 }

我想知道如何从调用此方法的其他方法访问List[Int]

换句话说,

val result = downloadPage("localhost") 

那么将来List[Int]的方法应该是什么?

我尝试过使用map方法,但无法成功完成此操作。

6 个答案:

答案 0 :(得分:26)

  

成功案例(listInt)=>我想返回listInt,我无法弄清楚如何做到这一点。

最佳做法是返回值。相反,您只需将未来(或使用mapflatMap等转换的版本)传递给需要此值的所有人,他们就可以添加自己的onComplete

如果你确实需要返回它(例如在实现遗留方法时),那么你唯一能做的就是阻止(例如用Await.result),你需要决定等待多长时间。

答案 1 :(得分:11)

您需要等待将来完成以获得某个时间跨度的结果,这是可行的:

  import scala.concurrent.duration._

  def downloadPage(url: URL) = Future[List[Int]] {
    List(1,2,3)
  }

  val result = downloadPage("localhost")

  val myListInt = result.result(10 seconds)

理想情况下,如果您使用Future,则不希望阻止执行线程,因此您可以将处理Future结果的逻辑移至onComplete 1}}方法,类似这样:

  result.onComplete({
    case Success(listInt) => {
      //Do something with my list
    }
    case Failure(exception) => {
      //Do something with my error
    }
  })

答案 2 :(得分:5)

我希望你已经解决了这个问题,因为它在2013年被问到了,但也许我的回答可以帮助其他人:

如果您使用的是Play Framework,它支持异步操作(实际上所有操作都是异步内部)。创建异步操作的简单方法是使用Action.async()。您需要为此功能提供Future[Result]

现在,您可以使用Scala的map,flatMap,for-comprehension或async / await,从Future[List[Int]]转换为Future[Result]。这是Play Framework文档中的一个示例。

import play.api.libs.concurrent.Execution.Implicits.defaultContext

def index = Action.async {
  val futureInt = scala.concurrent.Future { intensiveComputation() }
  futureInt.map(i => Ok("Got result: " + i))
}

答案 3 :(得分:5)

你可以做那样的事情。如果Await.result方法中给出的等待时间小于awaitable执行的等待时间,则您将有一个TimeoutException,并且您需要处理错误(或任何其他错误) )。

import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
import scala.concurrent.duration._

object MyObject {
    def main(args: Array[String]) {

        val myVal: Future[String] = Future { silly() }

        // values less than 5 seconds will go to 
        // Failure case, because silly() will not be done yet
        Try(Await.result(myVal, 10 seconds)) match {
            case Success(extractedVal) => { println("Success Happened: " + extractedVal) }
            case Failure(_) => { println("Failure Happened") }
            case _ => { println("Very Strange") }
        }      
    }

    def silly(): String = {
        Thread.sleep(5000)
        "Hello from silly"
        }
}

答案 4 :(得分:3)

我发现想到未来的最佳方式是一个盒子,在某些时候,它会包含你想要的东西。未来的关键是你永远不会打开盒子。试图强行打开盒子将导致你阻塞和悲伤。相反,您通常使用map方法将Future放在另一个更大的框中。

以下是包含String的Future的示例。当Future完成时,则调用Console.println:

$results = $rets->Search(
    'Property', 
    'Listing', 
    "(MatrixModifiedDT=1980-01-01T00:00:00+)", 
    ["Limit"=>1]
);

请注意,在这种情况下,我们调用main方法然后...完成。由全局ExecutionContext提供的字符串的Future执行调用Console.println的工作。这很好,因为当我们放弃控制someString何时出现以及何时调用Console.println时,我们让系统自行管理。相反,看看当我们试图强行打开盒子时会发生什么:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object Main {

  def main(args:Array[String]) : Unit = {
    val stringFuture: Future[String] = Future.successful("hello world!")
    stringFuture.map {
      someString =>
        // if you use .foreach you avoid creating an extra Future, but we are proving
        // the concept here...
        Console.println(someString)
    }
  }
}

在这种情况下,我们必须等待 - 让一个线程翻转它的拇指 - 直到我们得到someString。我们打开了这个盒子,但我们不得不征用系统的资源来获取它。

答案 5 :(得分:0)

尚未提及,因此我想强调结合使用Future的理解和顺序执行与并行执行的区别。

例如,对于顺序执行:

object FuturesSequential extends App {

  def job(n: Int) = Future {
    Thread.sleep(1000)
    println(s"Job $n")
  }

  val f = for {
    f1 <- job(1)
    f2 <- job(2)
    f3 <- job(3)
    f4 <- job(4)
    f5 <- job(5)
  } yield List(f1, f2, f3, f4, f5)
  f.map(res => println(s"Done. ${res.size} jobs run"))
  Thread.sleep(6000) // We need to prevent main thread from quitting too early
}

对于并行执行(请注意Future在理解之前)

object FuturesParallel extends App {

  def job(n: Int) = Future {
    Thread.sleep(1000)
    println(s"Job $n")
  }

  val j1 = job(1)
  val j2 = job(2)
  val j3 = job(3)
  val j4 = job(4)
  val j5 = job(5)

  val f = for {
    f1 <- j1
    f2 <- j2
    f3 <- j3
    f4 <- j4
    f5 <- j5
  } yield List(f1, f2, f3, f4, f5)
  f.map(res => println(s"Done. ${res.size} jobs run"))
  Thread.sleep(6000) // We need to prevent main thread from quitting too early
}