你应该注意类型。在这里,您从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
}