ver*_*tti 2 scala initialization lazy-evaluation lazy-initialization
我的游戏有一个像这样的声音对象:
object Sounds {
SoundFactory.setAssetBasePath("mfx/")
val EXPLOSION_0 = ESound("explosion1.ogg")
val EXPLOSION_1 = ESound("explosion2.ogg")
val EXPLOSION_2 = ESound("explosion3.ogg")
val IMPACT_0 = ESound("impact1.ogg", 0.4f)
val IMPACT_1 = ESound("impact2.ogg", 0.4f)
val IMPACT_2 = ESound("impact3.ogg", 0.4f)
val BONUS = ESound("bonus.ogg", 0.7f)
// -- snip --
def load() {
println("Sounds loaded")
}
case class ESound(sound_file: String, volume: Float = 1) {
private val sound = SoundFactory.createSoundFromAsset(AndEngine.engine.getSoundManager, AndEngine.activity.get, sound_file)
sound.setVolume(volume)
sound.setLoopCount(0)
def play() { sound.play() }
}
}
Run Code Online (Sandbox Code Playgroud)
为简洁起见,我删除了许多方法等.但基本的想法是Scala懒惰地load()将对象初始化,所以我第一次在这个对象上调用一些方法()它会被初始化.这将在例如纹理加载等之后完成.
但是使用上面的代码,我第一次按下游戏中的某个菜单按钮时,我得到一个长时间的停顿,因为它只会加载所有这些声音(由SoundFactory.createSound...构造函数中的引起).
现在,如果我将load方法更改为以下:
println("Sounds loaded, " + BONUS.toString)
Run Code Online (Sandbox Code Playgroud)
所有声音都正确加载.
那么,为什么会这样呢?Scala如何以及为什么初始化Sounds对象以便我可以调用load()但不在构造函数部分中加载它自己的值?伴随对象初始化的规则是什么?
根据Scala规范的 5.4节:
请注意,对象定义定义的值是懒惰实例化的.新的m $ cls构造函数不是在对象定义点进行评估,而是在程序执行期间第一次取消引用m时进行评估(可能根本不会).在构造函数的评估过程中再次取消引用m的尝试导致无限循环或运行时错误.在评估构造函数时尝试取消引用的其他线程会阻塞,直到评估完成.
配对对象应该在第一次被引用时构建 - 我认为这也是你的理解.这适用于以下示例:
object Sounds {
val EXPLOSION_0 = ESound("EXPLOSION_0")
def load() { println("loaded") }
case class ESound(file: String) {
private val sound = {
println("waiting 1s before loading " + file)
Thread.sleep(1000)
"sound from " + file
}
}
}
object C extends App {
Sounds.load()
}
Run Code Online (Sandbox Code Playgroud)
打印:
[info] Running C
waiting 1s before loading EXPLOSION_0
loaded
Run Code Online (Sandbox Code Playgroud)
因此,您的意外行为可能来自您尚未发布的部分.