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