【问题标题】:Scala - how to avoid closure?Scala - 如何避免关闭?
【发布时间】:2012-04-18 10:39:49
【问题描述】:

将函数作为参数传递给类构造函数时如何避免闭包?

我的类构造函数接受() => Unit 类型的函数。在程序工作过程中,我想从可变映射中访问一个键值对,该映射在使用构造函数创建对象时未定义

val cats = scala.collection.mutable.Map[String, Cat]

class Trigger(period: Long, f: () => Unit) {

  //pseudocode:
  when period passes, f()

}

someWonderfulObject += new Trigger (1000, () => cats("Hershy").meow)

cats += ("Hershy" -> Cat())

然后,当美妙的对象触发它的触发器时,我得到没有像“Hershy”这样的键的错误。我得出结论,显然,这是由于 f 传递给 Trigger cons 在没有“Hershy”的状态下被关闭。

我现在的问题是 - 如何避免 Scala 在此处使用闭包,而是查看 cats 的实际状态?

更新:

“当周期过去”的代码是这样的:

def update(tpf: Float) {
  timePassed += tpf
  if(timePassed > period) f()
}

tpf 值来自上面,所以这一切似乎都正常。

更新:

我发现问题出在另一个完全不相关的地方,我混淆了所有这些东西的容器。但是,谢谢大家,我从答案中学到了一些东西。

【问题讨论】:

  • 你的猫是一个val,持有一个可变集合的引用。闭包不会克隆您的对象,理论上它唯一可以做的就是复制 cats 的值(参考)。但由于catsval,换句话说,它是一个常数,这不会是任何问题的根源。
  • 顺便说一句,这怎么编译:("Hershy" -> Cat)Cat 是一个类,它本身不是 Cat。我猜这只是伪代码——当其他人试图调试他们从未见过的代码时,它总是会让人感到困惑。
  • 哦,对不起,它应该是 Cat()
  • 你的代码行为是时间敏感和线程不安全的。您正在改变地图,然后从另一个线程中读取它。不能保证添加映射条目的代码必须在您的时间触发器之前执行,即使这样做,仍然不能保证计时器线程会观察到更改。这是否是您的直接问题尚不清楚。
  • 能否请您出示when period passes 的代码。请注意,如果这个阻塞,整个时间将花费在new Trigger 调用期间,因此,您的地图填充代码甚至还没有执行!

标签: scala closures


【解决方案1】:

闭包不会做这样的事情(这将很难指定,性能很差,并使整个事情变得无用)。闭包可能包含对猫的引用,或对包含猫的实例的引用,而不是副本。

此代码按预期工作:

val cats = collection.mutable.Map[String, String]()

class Trigger(name: String, f: () => Unit) {
  def fire = {
    println("Fire " + name)
    f()
  }
}

val trigger = new Trigger("calling Hershy", () => println(cats("Hershy")))
cats += "Hershy" -> "meow"
trigger.fire // prints Fire calling Hershy

关闭没有问题,我怀疑这在您的示例中没有出现。

【讨论】:

  • 很好的例子,但永远不要忘记猫“喵”;-) 你忘记了那个关键点,除了打印“火叫赫希”之外,它还打印“喵”;如果没有“喵”,你的答案就不会是一个简单的闭包示例......
猜你喜欢
  • 2018-12-23
  • 2016-07-30
  • 1970-01-01
  • 2012-02-21
  • 2010-12-14
  • 2016-03-31
  • 2019-07-02
  • 2018-12-21
  • 1970-01-01
相关资源
最近更新 更多