Scala Newb问题 - 关于范围和变量

时间:2009-11-24 01:23:20

标签: scala scoping

我正在解析XML,并继续发现自己编写的代码如下:

val xml = <outertag>
<dog>val1</dog>
<cat>val2</cat>
</outertag>

var cat = ""
var dog = ""

for (inner <- xml \ "_") {
  inner match {
    case <dog>{ dg @ _* }</dog> => dog = dg(0).toString()
    case <cat>{ ct @ _* }</cat> => cat = ct(0).toString()
  }
}

/* do something with dog and cat */

它让我很烦,因为我应该能够将cat和dog声明为val(不可变),因为我只需要设置它们一次,但我必须让它们变得可变。除此之外,似乎必须有更好的方法在scala中执行此操作。有什么想法吗?

3 个答案:

答案 0 :(得分:3)

这里有两个(现在是三个)可能的解决方案。第一个很快很脏。您可以在Scala解释器中运行整个位。

val xmlData = <outertag>
<dog>val1</dog>
<cat>val2</cat>
</outertag>

// A very simple way to do this mapping.
def simpleGetNodeValue(x:scala.xml.NodeSeq, tag:String) = (x \\ tag).text

val cat = simpleGetNodeValue(xmlData, "cat")
val dog = simpleGetNodeValue(xmlData, "dog")

cat将为“val2”,dog将为“val1”。

请注意,如果找不到任一节点,将返回空字符串。你可以解决这个问题,或者你可以用稍微惯用的方式来编写它:

// A more idiomatic Scala way, even though Scala wouldn't give us nulls.
// This returns an Option[String].
def getNodeValue(x:scala.xml.NodeSeq, tag:String) = {
  (x \\ tag).text match {
    case "" => None
    case x:String => Some(x)
  }
}

val cat1 = getNodeValue(xmlData, "cat") getOrElse "No cat found."
val dog1 = getNodeValue(xmlData, "dog") getOrElse "No dog found."
val goat = getNodeValue(xmlData, "goat") getOrElse "No goat found."  

cat1将为“val2”,dog1将为“val1”,goat将为“找不到山羊。”

更新:这是获取标签名称列表并将其匹配作为Map [String,String]返回的另一种便捷方法。

// Searches for all tags in the List and returns a Map[String, String].
def getNodeValues(x:scala.xml.NodeSeq, tags:List[String]) = {
  tags.foldLeft(Map[String, String]()) { (a, b) => a(b) = simpleGetNodeValue(x, b)}
}

val tagsToMatch = List("dog", "cat")
val matchedValues = getNodeValues(xmlData, tagsToMatch)

如果你运行,matchedValues将为Map(dog -> val1, cat -> val2)

希望有所帮助!

更新2 :根据Daniel的建议,我正在使用双反斜杠运算符,它将进入子元素,这可能会随着XML数据集的发展而变得更好。

答案 1 :(得分:2)

scala> val xml = <outertag><dog>val1</dog><cat>val2</cat></outertag>
xml: scala.xml.Elem = <outertag><dog>val1</dog><cat>val2</cat></outertag>

scala> val cat = xml \\ "cat" text
cat: String = val2

scala> val dog = xml \\ "dog" text
dog: String = val1

答案 2 :(得分:1)

考虑在函数中包装XML检查和模式匹配,该函数返回作为元组(Tuple2[String, String])所需的多个值。但请停下来考虑一下:看起来可能无法匹配任何dogcat元素,这会让您为一个或两个元组组件返回null。也许您可以返回Option[String]的元组,或者如果任何一个元素模式无法绑定,则抛出。

在任何情况下,通常可以通过将组成语句包装到函数中来生成表达式来解决这些初始化问题。掌握了表达式后,可以使用其评估结果初始化常量。