Scala Monad-没有for语句(优雅的方法来检查null属性)

时间:2018-07-12 14:06:14

标签: java scala monads

假设我只有一个顶级对象,另外两个对象嵌套在其中作为属性:

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

有没有一种方法可以在不将顶级对象放入集合的情况下获得姓氏?

2 个答案:

答案 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