隐含的变量和期货

时间:2014-05-08 20:48:50

标签: scala

我有一个使用隐式var和期货的问题。假设以下情形:

object ImplicitMess extends App {

  implicit var curStr = "Initial Value"

  def useImplicit(implicit str: String) = {
    println(str)
    str.length
  }

  useImplicit

  val ftr = future {
    Thread.sleep(1000)
    useImplicit
  }

  curStr = "Modified Value"

  Await.ready(ftr, 2.seconds)

}

在创建未来的时间内,隐含值是"初始值"但是当它实际执行时,该值是"修改值",这不是所希望的行为。 这是因为未来的身体正在引用var而不是当前值。

所以我想出的第一个解决方案是在一个块中捕获一个val中的var值,认为这将使隐含的更接近并解决模糊性。但由于模糊的隐含价值,它甚至无法编译。错误。

...
  val ftr = {
    implicit val str = curStr
    future {
      Thread.sleep(1000)
      useImplicit
    }
  }
...

所以,我希望拥有的是一种方法来包装异步代码(在期货上的任何操作),在异步代码定义时使用固定的隐式值,而不是在评估时

对于一个库来说,这个例子是问题的一个非常简化的版本,所以我需要这样的东西有两个原因:1)为了达到理想的行为。 2)让用户有责任了解所有复杂性。

...
  val ftr = fixImplicit {
    // All within this block will use the current value of the implicit var
    future {
      Thread.sleep(1000)
      useImplicit
    }
  }
...

你认为这可能吗?
谢谢。

[已编辑]为所有对var使用感到恐惧的人添加一些上下文。

我需要这个来改进我的一个项目,即akka-contextual-actor(github),它是关于在actor之间传播一个共同的上下文,避免使用方面库。因此,主要需求之一是透明地完成它,而不是明确地传递隐式。

我做了很多依赖隐式转换的包装和解包消息,除了在actor中使用var中的上下文以使其在接收中可用之外,我没有其他选择。您可以查看代码以了解我是如何做到的。

再次感谢。

加斯。
@ktonga

2 个答案:

答案 0 :(得分:2)

首先,您确定需要使用变量吗? Vals更具惯用性。

如果您需要在将来完成之前访问var的值,您只需保存副本然后显式使用该参数:

  val ftr = future {
    val saved = curStr
    Thread.sleep(1000)
    useImplicit(saved)
  }

答案 1 :(得分:2)

另一个答案是你必须暗示隐含的。

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

object ImplicitMess extends App {

  implicit var curStr = "Initial Value"

  def useImplicit(implicit str: String) = {
    println(str)
    str.length
  }

  useImplicit

  val ftr = {
    implicit val curStr = ImplicitMess.curStr
    future {
    Thread.sleep(1000)
    useImplicit
  }}
  curStr = "Modified Value"

  Await.ready(ftr, 2.seconds)

}

// Exiting paste mode, now interpreting.

warning: there were 1 deprecation warning(s); re-run with -deprecation for details
defined object ImplicitMess

scala> ImplicitMess main null
Initial Value
Initial Value

当然,关于val的建议仍然适用。

更新

如果我们正在讨论this context,那么我认为this answer会解决这个问题。