2011-09-22 56 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方法只是表明它們需要延遲實例化,但有時單獨的工廠方法肯定會適用)。 –

相關問題