2011-09-22 59 views
2

我想要创建一个列表Chicken s和Egg。他们被定义为:是否可以在for表达式中使用lazy值?

class Chicken (val name: String, e: => Egg) { lazy val child = e } 

class Egg (val name: String, c: => Chicken) { lazy val parent = c } 

和一对必须实例懒惰,因为它们包含循环引用:

def fillBarn { 
    lazy val chicken: Chicken = new Chicken("abc", egg) 
    lazy val egg: Egg = new Egg("def", chicken) 
    } 

我有,我想创建鸡/鸡蛋名称的列表。不幸的是,以下不会编译:

val names = List("C1 E1", "C2 E2", "C3 E3") 
val list = for { 
    Array(cn, en) <- names.map(_.split(" ")) 
    lazy c: Chicken = new Chicken(cn, e) 
    lazy e: Egg = new Egg(en, c) 
} yield (c, e) 

但没有糖它:

val list = names.map(_.split(" ")).map { 
    case Array(cn, en) => 
    lazy val c: Chicken = new Chicken(cn, e) 
    lazy val e: Egg = new Egg(en, c) 
    (c, e) 
} 

现在可以说是在这个简单的情况下,它更好,而不用于表达,可是如果我不希望使用for-expression,可以吗?

我也认识到,在这个简单例子,我可以一个yield块内构建ChickenEgg的情况下,但是这通常不会是真实的,说,如果我想要做的基于实例一些额外的过滤和映射。

回答

5

那么,在这个(而且可能还更先进的情况下),你总是可以适应fillBarn方法给你,你需要的东西(这是使这个方法的意义无论如何的唯一途径):

def fillBarn(c: String, e: String) = { 
    lazy val chicken: Chicken = new Chicken(c, egg) 
    lazy val egg: Egg = new Egg(e, chicken) 
    (chicken, egg) 
} 

然后

val list = for { 
    Array(cn, en) <- names.map(_.split(" ")) 
    (c, e) = fillBarn(cn, en) 
} yield (c, e) 

当然,如果你想,有在定义fillBarn方法没有必要。你也可以做到在线:

val list = for { 
    Array(cn, en) <- names.map(_.split(" ")) 
    (c, e) = { 
    lazy val chicken: Chicken = new Chicken(cn, egg) 
    lazy val egg: Egg = new Egg(en, chicken) 
    (chicken, egg) 
    } 
} yield (c, e) 

一个for声明斯卡拉一般结构是固定的。只有flatMap/map/foreach<-或直接分配给一个新的变量名,以便以后使用=。但是在这些陈述的右边,只要这个块返回适当的对象,你就可以在块中放入任何你喜欢的东西。

+0

太棒了!非常感谢。我认为内联模式是我正在寻找的(这里的fillBarn方法只是表明它们需要延迟实例化,但有时单独的工厂方法肯定会适用)。 –

相关问题