我有一个使用隐式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
答案 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会解决这个问题。