你应该注意类型。在这里,你从
m : Map[String, Any]
开始作为你的累加器。你与一个字符串
x
结合,并调用
get
,它返回一个
Option[Object]
。为了继续,你必须检查是否有值,检查这个值是否是一个
Map
,进行强制转换(由于类型擦除而不受检查,因此危险)。
我认为问题出在你的结构类型上,Map[String,Any] 不太准确地表示了你所拥有的。
假设你改用如下方式:
sealed trait Tree
case class Node(items: Map[String, Tree]) extends Tree
case class Leaf(s: String) extends Tree
您可以添加一些助手函数来使声明树更加容易。
object Tree {
implicit def fromString(s: String) = Leaf(s)
implicit def fromNamedString(nameAndValue: (String, String))
= (nameAndValue._1, Leaf(nameAndValue._2))
}
object Node {
def apply(items: (String, Tree)*) : Node = Node(Map(items: _*))
}
那么声明树就像你第一个版本一样容易,但类型更加精确。
m = Node("email" -> "a@b.com", "background" -> Node("language" -> "english"))
你可以在 trait Tree
中添加方法。
def get(path: String*) : Option[Tree] = {
if (path.isEmpty) Some(this)
else this match {
case Leaf(_) => None
case Node(map) => map.get(path.head).flatMap(_.get(path.tail: _*))
}
}
def getLeaf(path: String*): Option[String]
= get(path: _*).collect{case Leaf(s) =>s}
或者如果您更愿意使用折叠函数
def get(path: String*) = path.foldLeft[Option[Tree]](Some(this)) {
case (Some(Node(map)), p) => map.get(p)
case _ => None
}
m("background").asInstanceOf[Map[String,String]]("language")
。m("background")
是一个java.lang.Object
,你需要在某个地方进行额外的转换/匹配。然而,这种数据结构似乎有点奇怪,你应该考虑一些更面向对象的东西。 - Tomasz Nurkiewicz