假设我只有一个顶级对象,另外两个对象嵌套在其中作为属性:
class Human(val name: String, val child: Human)
val anita = new Human("Anita", null)
val david = new Human("David", anita)
val fabrizio = new Human("Fabrizio", david)
如果我必须让最后一个孩子的名字开始使用fabrizio,我需要做很多空检查控件:
if(fabrizio != null)
if(fabrizio.child!= null)
if(fabrizio.children.child!= null)
println(fabrizio.child.child.name)
我在scala上发现了这种“语法糖”,但它似乎只适用于集合:
println( for(x <- fabrizio.child; y <- x.child; z <- y.child) yield z.name)
事实上,它抱怨:
value flatMap is not a member of Playground.this.Human
有没有一种方法可以在不将顶级对象放入集合的情况下获得姓氏?
答案 0 :(得分:2)
它不是收藏专用的。 Scala的理解力降低了嵌套flatMap
调用和最终map
的难度。不用在代码中使用null
,而是使用Option[T]
来表达以下事实:Human
及其子元素可能会或可能不会被定义:
final case class Human(name: String, children: Option[Human])
val maybeAnita: Option[Human] = Some(Human("Anita", None))
val maybeDavid: Option[Human] = Some(Human("David", maybeAnita))
val maybeFabrizio: Option[Human] = Some(Human("Fabrizio", maybeDavid))
现在您可以:
val maybeName: Option[String] = for {
fabrizio <- maybeFabrizio
children <- fabrizio.children
nestedChildren <- children.children
} yield nestedChildren.name
答案 1 :(得分:2)
Yuval使用Option
的建议是处理null
的惯用且简单的方法,并且是极好的建议。我想补充一点:
如果要查找最后一个孩子的名字,则可以简单地创建一个函数:
def lastChild(person: Human, isChild: Boolean = false): Option[Human] = {
person.children match {
case Some(child) => lastChild(child, true)
case None if isChild => Some(person)
case _ => None
}
}
您还可以添加一个level变量以确保一定的世代:
def nthChild(person: Human, level: Int, isChild: Boolean = false): Option[Human] = {
person.children match {
case Some(child) if (level > 0) => lastChild(child, (level - 1), true)
case _ if ((level == 0) && isChild) => Some(person)
case _ => None
}
}
附带说明:如果每个Human
只能有一个孩子,为清楚起见,该字段应命名为child