2011-04-09 65 views
1

嘿家伙, 即时通讯工程在斯卡拉的一个项目,我遇到了非常奇怪的问题。这是代码的一部分:对象被随机“变”为空

class Entity(val id:String){ 
    override def toString = id 
} 

class RequirementType 
case class DependsEither(t:List[(Entity,Int)]) extends RequirementType 
case class Depends(t:(Entity,Int)) extends RequirementType 

class BuildableEntity(override val id:String, 
       val mineralCost:Int, 
       val gasCost:Int, 
       val buildTime:Int, 
       val buildCount:Int, 
       val supplyCount:Int, 
       val req:List[RequirementType], 
       val onBuildStart: GameState => GameState,  
       val onBuildFinish: GameState => GameState 
      )extends Entity(id) 

class SimpleBuilding(id:String, 
     mineralCost:Int, 
     gasCost:Int, 
     buildTime:Int, 
     req:List[RequirementType] 
) extends BuildableEntity(id,mineralCost,gasCost,buildTime,1,0,req:::List(ConsumesOnStart((Drone,1))),{s=>s},{x=>x}) 
object SpawningPool extends SimpleBuilding("spawningPool",200,0,65,List(DependsEither(List((Hatchery,1),(Lair,1),(Hive,1))))) 
object Lair extends SimpleBuilding("lair",150,100,80,List(ConsumesOnFinish(Hatchery,1),Depends(SpawningPool,1))) 
object InfestationPit extends SimpleBuilding("infestationPit",100,100,50,List(DependsEither(List((Lair,1),(Hive,1))))) 

现在,当我调用的println(Lair.req),它有时打印为

列表(ConsumesOnFinish((孵化,1)),Depends中((NULL,2)),ConsumesOnStart((无人驾驶飞机,1)))

,有时作为

列表(ConsumesOnFinish((孵化场,1)), 取决于((spawningPool,2)),ConsumesOnStart((无人驾驶飞机,1)))

请,如果任何人有什么可能是任何想法出错了,我会永远爱你。我不知道它为什么会这样做。我有更多的扩展SimpleBuilding,但他们似乎正常工作

编辑: 我还应该提到编译后的结果改变。我的意思是,当我运行单元测试时,它有时显示为空,有时显示为正确的实例。

+0

你还没有发布'Depends'和'SpawningPool'这是奇怪发生的地方的代码... – huynhjl 2011-04-10 01:49:38

+0

愚蠢的我,固定。感谢您抽出宝贵时间,仔细查看! :] – Arg 2011-04-10 08:01:14

+0

我很确定它与SpairningPool的Lai对象的定义顺序有关。 – 2011-04-10 08:13:42

回答

3

这确实是循环依赖和初始化的情况。下面是一个较短的版本您的问题:

class X(val x: List[X]) 
object A extends X(List(B)) 
object B extends X(List(A)) 

object Main { 
    def main(args:Array[String]) { 
    println("A.x: " + A.x) 
    println("B.x: " + B.x) 
    } 
} 

这将打印:

$ scala -cp classes Main 
A.x: List([email protected]) 
B.x: List(null) 

您可以通过名称参数使用,使物体建设完成之后再使用:

class X(x0: => List[X]) { 
    lazy val x = x0 
} 
object A extends X(List(B)) 
object B extends X(List(A)) 

该修复适用于小型测试用例:

$ scala -cp classes Main 
A.x: List([email protected]) 
B.x: List([email protected]) 

基于此你可能会希望改变req:List[RequirementType]req0: => List[RequirementType]并且添加一个lazy val req = req0

如果这对你有用,我们应该重新提到对象初始化和循环依赖关系的问题。请注意,这与this question/answer非常相似。

+0

非常感谢您的回答。它似乎在工作!有点奇怪,没有编译时错误,我会预料到的。 – Arg 2011-04-11 14:18:58

3

Lair使用SpawningPool在其构造函数和相互。但那个时候,另一个不存在。

3

你已经在构造函数中有了递归定义,尽管我相信这是被支持的,但它看起来像是出了问题。你可以尝试懒惰的vals,看看问题是否消失?也就是说,

object X extends C("this",that,1) { /* code */ } 

成为

lazy val X = new C("this",that,1) { /* code */ }