在为NodeSeq编写自定义匹配器时遇到问题:

private def matchXML(expected: NodeSeq) = new Matcher[NodeSeq] {
  def apply(left: NodeSeq): MatchResult = MatchResult(left xml_== expected,
    "XML structure was not the same (watch spaces in tag texts)",
    "XML messages were equal")
}

可以编译,但是下面的代码段:
val expected : NodeSeq = ...
val xml : NodeSeq = ...
xml should matchXML(expected)

原因:
error: overloaded method value should with alternatives:
(beWord: XMLStripDecoratorTests.this.BeWord)XMLStripDecoratorTests.this.ResultOfBeWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
(notWord: XMLStripDecoratorTests.this.NotWord)XMLStripDecoratorTests.this.ResultOfNotWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
(haveWord: XMLStripDecoratorTests.this.HaveWord)XMLStripDecoratorTests.this.ResultOfHaveWordForSeq[scala.xml.Node] <and>
(rightMatcher: org.scalatest.matchers.Matcher[scala.collection.GenSeq[scala.xml.Node]])Unit
cannot be applied to (org.scalatest.matchers.Matcher[scala.xml.NodeSeq])
xml should (matchXML(expected))

任何想法,这意味着什么?

最佳答案

为什么无法进行类型检查:

类型检查器按以下方式工作。

xml.should(matchXML(expected))
  • 因为方法should不属于NodeSeq,所以编译器会尝试将xmlimplicit conversion查找为ShouldMatcher
    《 Scala编程》一书规定,这种隐式转换应该是最具体的:


  • 因为NodeSeq扩展了Seq[Node],所以以下功能
    convertToSeqShouldWrapper[T](o : scala.GenSeq[T]) : SeqShouldWrapper[T]
    因此,是所有其他应用中最具体的一个。

  • 该程序被重写为:
    `convertToSeqShouldWrapper(xml).should(matchXML(expected))`
    

    其中convertToSeqShouldWrapper(xml)SeqShouldWrapper[T],其中T = GenSeq[Node]
    should中的SeqShouldWrapper方法接受Matcher[T],它是T => MatchResult类型的函数。因此,它接受Matcher[GenSeq[Node]]

    由于T出现在箭头的左侧,因此匹配项不是T中的covariant,而是互变的。 NodeSeqGenSeq[Node],所以Matcher[GenSeq[Node]]Matcher[NodeSeq],而不是相反。这解释了上述错误,其中should方法无法接受Matcher[NodeSeq]并且需要Matcher[GenSeq[Node]]

    2解决方案
  • NodeSeq的所有实例替换为GenSeq[Node],以便在任何地方都匹配类型。
  • 或者,使用转换函数显式地包装xml。
    convertToAnyShouldWrapper(xml).should(matchXML(expected))
  • 09-25 20:16