Scala 隐式变量与未来
我在使用隐式var和futures时遇到了一个问题。假设以下场景:Scala 隐式变量与未来,scala,Scala,我在使用隐式var和futures时遇到了一个问题。假设以下场景: 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)
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值,认为这将限定隐式closer的范围并解决歧义。但由于“不明确的隐式值”错误,它甚至无法编译
所以,我希望有一种方法来包装异步代码(任何期货操作),在定义异步代码时使用固定的隐式值,而不是在计算异步代码时
对于一个库来说,这些示例是问题的一个简化版本,所以我需要这样做有两个原因: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 context actor(),它是关于在参与者之间传播公共上下文,避免使用方面库。因此,主要需求之一是透明地执行,而不显式地传递隐式 我在很大程度上依赖于隐式转换来包装和解包消息,除了在actor中的var中包含上下文以使其在receive中可用之外,我没有其他选择。你可以看看代码,看看我是怎么做的 再次感谢 加斯顿。
@ktonga首先,您确定需要使用VAR吗?VAL更为惯用 如果您需要在将来完成之前访问var的值,您可以只保存一个副本,然后显式使用该参数:
val ftr = future {
val saved = curStr
Thread.sleep(1000)
useImplicit(saved)
}
首先,您确定需要使用VAR吗?VAL更为惯用 如果您需要在将来完成之前访问var的值,您可以只保存一个副本,然后显式使用该参数:
val ftr = future {
val saved = curStr
Thread.sleep(1000)
useImplicit(saved)
}
另一个答案是,您必须隐藏隐式
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的建议仍然适用
更新:
如果我们谈论的是,那么我认为可以解决这个问题。另一个答案是,你必须隐藏隐含的信息
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的建议仍然适用
更新:
如果我们讨论的是隐式VAR,那么我认为它解决了这一问题。我从未意识到隐式VAR甚至是可能的,在Scala中也没有比这更可怕的了。你绝对确定你必须这样做吗?var capture@TravisBrown你的隐式执行上下文应该完全是一个var,所以你可以随时切换它!“嗨,特拉维斯布朗,你们用“任何更可怕的事情”让我大笑起来。我确信第一个答案或评论是警告我使用vars。我知道这很糟糕。我对这个问题进行了编辑,添加了更多的上下文。我从未意识到隐式变量甚至是可能的,在Scala中,我想不出有什么比这更可怕的了。你绝对确定你必须这样做吗?var capture@TravisBrown你的隐式执行上下文应该完全是一个var,所以你可以随时切换它!“嗨,特拉维斯布朗,你们用“任何更可怕的事情”让我大笑起来。我确信第一个答案或评论是警告我使用vars。我知道这很糟糕。我编辑了这个问题以添加更多的上下文。谢谢@Gangstead,我知道这个解决方案,但遗憾的是,显式传递值不是一个选项。我编辑这个问题是为了解释原因。谢谢@Gangstead,我知道这个解决方案,但遗憾的是,显式传递值不是一个选项。我编辑这个问题是为了解释原因。谢谢@som snytt,这似乎是一个有效的解决方案,正如预期的那样。最好不要把这个责任放在lib的用户端(问题编辑),但到目前为止这是可以接受的。谢谢@som snytt,这似乎是一个有效的解决方案,正如预期的那样工作。最好不要把这个责任放在lib的用户端(问题编辑),但到目前为止这是可以接受的。