我对scala相当新鲜。我有这个方法来过滤所有来自Jsoup库的Elements-以给定的命名空间开头。
def getElementsByNamespace(element: org.jsoup.nodes.Element, namespace: String) : org.jsoup.select.Elements = {
val elements =
for {
el <- element.select("*")
if el.tagName().startWith(namespace+":")
} yield el
elements
}
在此示例<root><server:cpu></server:cpu><server:ram></server:ram><a></a></root>
中,该方法将获取以server
问题是scala将el <- element.select("*")
转换为Any
而不是Element
,这是方法select返回的类型(它实际上返回一个Elements对象或一个ArrayList)< / p>
因此,当我调用if el.tagName().startWith(namespace+":")
时,找不到tagName(),因此代码无法编译。
我尝试过滤器,withFilter等,但仍无法正常工作。
为什么会这样?如何让这段代码更好?
答案 0 :(得分:3)
问题是您需要在Scala和Java集合之间进行转换:
def getElementsByNamespace(element: org.jsoup.nodes.Element, namespace: String): org.jsoup.select.Elements = {
import collection.JavaConverters._
val elements = for {
el <- element.select("*").asScala
if el.tagName().startsWith(s"$namespace:")
} yield el
new Elements(elements.asJava)
}
为了在Scala中迭代集合,您可以使用flatMap
,map
或者用于理解。没有其他方法(如Java中的for
和foreach
循环)。
但问题是Java集合不是直接支持的,因为它们需要在它们上定义flatMap
方法。 flatMap
是迭代的本质(另外两种方法也是基于flatMap
定义的)。
这就是为什么你需要将Elements
类型的变量转换为Scala集合(导入JavaConverters._
并在Java集合上调用asScala
方法)。
最后,您需要构造一个新的Elements
但是该类的构造函数,可以理解,只接受Java集合,因此您需要将您的for comprehension(Scala集合)的结果转换为一个Java集合。
答案 1 :(得分:1)
我认为您可能想要添加导入scala.collenction.JavaConversions._
事情是Elements
类,select
方法返回的类不支持理解 - 因为它是ArrayList
的扩展,因此没有map
,{{1} }和flatMap
方法 - 除非您隐式转换为其中一个scala集合。