Доступ к стоимости, возвращаемой фьючерсами scala
Я новичок в фьючерсах scala, и у меня есть сомнения относительно возвращаемого значения фьючерсов scala.
Итак, в целом синтаксис для будущего scala -
def downloadPage(url: URL) = Future[List[Int]] {
}
Я хочу знать, как получить доступ к List[Int]
из другого метода, который вызывает этот метод.
Другими словами,
val result = downloadPage("localhost")
то каким должен быть подход, чтобы получить List[Int]
из будущего?
Я попытался использовать метод карты, но не смог сделать это успешно.
Ответы
Ответ 1
Случай успеха (listInt) => Я хочу вернуть listInt, и я не могу понять, как это сделать.
Лучшая практика заключается в том, что вы не возвращаете значение. Вместо этого вы просто передаете будущее (или версию, преобразованную с map
, flatMap
и т.д.) flatMap
, кому нужно это значение, и они могут добавить свое собственное onComplete
.
Если вам действительно нужно вернуть его (например, при реализации устаревшего метода), то единственное, что вы можете сделать, - это заблокировать (например, с помощью Await.result
), и вам нужно решить, как долго ждать.
Ответ 2
Вам нужно подождать, пока закончится будущее, чтобы получить результат, заданный несколько раз, вот что-то, что сработало бы:
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
, что-то например:
result.onComplete({
case Success(listInt) => {
//Do something with my list
}
case Failure(exception) => {
//Do something with my error
}
})
Ответ 3
Я надеюсь, что вы уже решили это, так как он был задан в 2013 году, но, возможно, мой ответ может помочь кому-то еще:
Если вы используете Play Framework, он поддерживает async Actions (фактически все действия являются асинхронными внутри). Простым способом создания асинхронного действия является Action.async()
. Вам необходимо предоставить Future[Result]
для этой функции.
Теперь вы можете просто сделать преобразования с Future[List[Int]]
до Future[Result]
с помощью карты Scala, flatMap, для понимания или асинхронного/ждущего. Вот пример из документации 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))
}
Ответ 4
Вы можете сделать что-то подобное. Если время ожидания, указанное в методе 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"
}
}
Ответ 5
Лучший способ, которым Айв подумал о будущем, - это коробка, которая в какой-то момент будет содержать то, что вы хотите. Главное в будущем - это то, что вы никогда не открываете коробку. Попытка заставить открыть коробку приведет вас к блокированию и печали. Вместо этого вы помещаете Будущее в другой, более крупный ящик, обычно используя метод карты.
Вот пример будущего, который содержит строку. Когда будущее завершается, 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)
}
}
}
Обратите внимание, что в этом случае вызывается основной метод, а затем... завершение. Строки Future, предоставляемые глобальным ExecutionContext, выполняют работу при вызове Console.println. Это здорово, потому что, когда мы отказываемся от контроля над тем, когда someString будет там, и когда Console.println будет вызван, мы позволяем системе управлять собой. В принципе, посмотрите, что происходит, когда мы пытаемся открыть окно:
val stringFuture: Future[String] = Future.successful("hello world!")
val someString = Future.await(stringFuture)
В этом случае нам нужно подождать - держите нить, крутящую большие пальцы, - пока мы не вернем someString. Мы открыли коробку, но нам пришлось командовать системными ресурсами, чтобы добраться до нее.