【问题标题】:Implicit vars and Futures隐式变量和期货
【发布时间】:2014-05-08 20:48:50
【问题描述】:

我在使用隐式 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 的 var 中以使其在接收中可用之外,我没有其他选择。您可以查看代码以了解我是如何做到的。

再次感谢。

加斯顿。
@ktonga

【问题讨论】:

  • 我从来没有意识到隐式变量甚至是可能的,并且在 Scala 中想不出比这更可怕的事情了。您确定必须这样做吗?
  • @TravisBrown 你的隐式执行上下文应该完全是一个 var,所以你可以随时切换它!
  • 嗨@TravisBrown,你用“更可怕的东西”让我大笑起来。我真的很确定第一个答案或评论会警告我不要使用 vars。我知道这很糟糕。我已经编辑了添加更多上下文的问题。

标签: scala


【解决方案1】:

另一个答案是你必须隐藏隐式。

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

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

更新:

如果我们谈论的是this context,那么我认为this answer 解决了它。

【讨论】:

  • 谢谢@som-snytt,这似乎是一个有效的解决方案,按预期工作。最好不要把这个责任放在 lib 的用户端(问题已编辑),但到目前为止它是可以接受的。
【解决方案2】:

首先,您确定需要使用 vars 吗? Vals 更惯用。

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

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

【讨论】:

  • 谢谢@Gangstead,我知道这个解决方案,但遗憾的是,明确传递值不是一种选择。我编辑了问题以解释原因。
猜你喜欢
  • 1970-01-01
  • 2011-10-06
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-01
相关资源
最近更新 更多