在为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
,所以编译器会尝试将xml
的implicit 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,而是互变的。 NodeSeq
是GenSeq[Node]
,所以Matcher[GenSeq[Node]]
是Matcher[NodeSeq]
,而不是相反。这解释了上述错误,其中should
方法无法接受Matcher[NodeSeq]
并且需要Matcher[GenSeq[Node]]
。2解决方案
NodeSeq
的所有实例替换为GenSeq[Node]
,以便在任何地方都匹配类型。 convertToAnyShouldWrapper(xml).should(matchXML(expected))