嵌套选项的惯用Scala

mon*_*ack 10 scala

假设我有一个Element对象(实际上来自JDom).它可能有一个名为"Group"的子元素,或者可能没有.如果是,那么它可能有一个名为"ID"的属性,或者它可能没有.我想要ID值(如果存在).

如果我会写Java.

private String getId(Element e) {
  for (Element child : e.getChildren()) 
    if (child.getName().equals("Group")) 
      for (Attribute a : child.getAttributes()) 
        if (a.getName().equals("ID"))
          return a.getValue();
  return null;
}
Run Code Online (Sandbox Code Playgroud)

在斯卡拉我也有

  val id = children.find(_.getName == "Group") match {
        case None => None
        case Some(child) => {
            child.getAttributes.asScala.find(_.getName == "ID") match {
                case None => None
                case Some(a) => Some(a.getValue)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

要么

val id = children.find(_.getName == "Group").
             map(_.getAttributes.asScala.find(_.getName == "ID").
             map(_.getValue).getOrElse("")).getOrElse("")
Run Code Online (Sandbox Code Playgroud)

他们中的哪一个,或者第三个,更具惯用性

Jea*_*let 14

这个怎么样?

val idOption = children
   .find(_.getName == "Group")
   .flatMap(_.getAttributes.asScala.find(_.getName == "ID"))
Run Code Online (Sandbox Code Playgroud)

或者,为了理解:

val idOption =
  for {
    child <- children.find(_.getName == "Group")
    id <- child.getAttributes.asScala.find(_.getName == "ID")
  } yield id
Run Code Online (Sandbox Code Playgroud)