是否可以在for-expressions中使用延迟值?

时间:2011-09-22 15:39:53

标签: scala lazy-evaluation

我有一个我要创建的ChickenEgg的列表。它们被定义为:

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,它会更好,但如果我确实想使用for-expression,我可以吗?

我也意识到,在这个简单的案例中,我可以在Chicken块内构建Eggyield个实例,但这通常不会成立,如果我想要根据实例做一些额外的过滤和映射。

1 个答案:

答案 0 :(得分:5)

好吧,在这个(也可以说是在更高级的情况下),你总是可以调整fillBarn方法来准确地提供你需要的东西(这是理解这种方法的唯一方法):< / p>

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)

Scala中for语句的一般结构是固定的。只有flatMap / map / foreach<-或直接分配给新的变量名称,以便稍后与=一起使用。但是在这些语句的右侧,只要此块返回适当的对象,您就可以在块中放置任何您喜欢的内容。