变量的范围在Future的OnSuccess调用中发生了变化

时间:2014-05-03 15:35:32

标签: scala scope akka

我需要找回在Future的onSuccess块中更改的变量。这是我的示例代码。

def futureFunction(arg:Any):Any = { 
  implicit val timeout = Timeout(10 seconds) 
  var ret:Any = None
  val f: Future[Any] = someActor ? arg
    f.onSuccess {
      case a:String => {
        ret = 1 
        println(ret) //prints "1" 
      }
      case a:Int => { 
        ret = 2 
        println(ret) //prints "2"
      }
    }
  ret //returns None
  }

ret返回为无,不会更改为12。那么这是否意味着无法返回onSuccess块中变量ret的值?然而,这似乎有效:

var a : Any = None

{
  a = 1
  println("inside "+ a ) //prints "inside 1"
}

println(a)   // prints "1"

我将来可以在onSuccess块中做些什么,以便将ret的值作为12返回,具体取决于未来的结果是整数还是串?对于scala,这种情况下的范围规则是什么? (我正在使用akka)。任何帮助表示赞赏。感谢。

2 个答案:

答案 0 :(得分:2)

这里的问题不是范围界定,而是时间问题。

  1. 首先,您要将ret初始化为None
  2. 然后,您将arg邮件发送给someActor,后者将返回未来。
  3. 之后,您设置了一个在将来完成时调用的函数,如果一切顺利,将在以后的某个时刻将值1或2分配给ret
  4. 最后,您立即返回ret的值,该值仍为None
  5. 在将来的某个时刻,未来完成,您的onSuccess函数会运行更改ret的值,然后打印它。但当然,这不能及时返回并改变之前已经返回的值。
  6. 所以,为了回答你的问题,你可以在onSuccess中做任何事情,它会及时返回并改变已经返回的值。但有两种选择。一种替代方法是阻止直到将来完成,然后确定是返回1还是2.另一种方法是返回Future[Int],以便调用者可以决定是否要阻止结果。这个代码实际上比你的代码简单:

    def futureFunction(arg:Any):Future[Int] = { implicit val timeout = Timeout(10 seconds) val f: Future[Any] = someActor ? arg f.map { case a:String => 1 case a:Int => 2 } }

    如果您确实需要阻止,可以在futureFunction内部或外部使用Await.result,具体取决于您要阻止的位置。

答案 1 :(得分:1)

futureFunction中,在ret处理程序运行之前返回onSuccess。当发生这种情况时,ret将变为12,但此时已为时已晚。

您要使用的是Future.map

someActor ? arg map {
  case a:String => 1
  case a:Int => 2 
}

请注意,futureFunction必须返回Future,否则您必须在函数内调用Await.result才能阻止,直到结果可用。