我在为 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
的一部分,编译器试图找到一个 implicit conversion对于xml
到ShouldMatcher
. 《Programming in Scala》一书规定,这种隐式转换应该是最具体的:
"Up through Scala 2.7, that was the end of the story. Whenever multiple implicit conversions applied, the compiler refused to choose between them. ... Scala 2.8 loosens this rule. If one of the available conversions is strictly more specific than the others, then the compiler will choose the more specific one. ... one implicit conversion is more specific than another if one of the following applies: The argument type of the former is a subtype of the latter’s. .."
因为
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
出现在箭头的左侧,匹配器不是 covariant在 T
, 但逆变。 NodeSeq
是 GenSeq[Node]
, 所以 Matcher[GenSeq[Node]]
是 Matcher[NodeSeq]
,而不是相反。这解释了上面的错误,其中方法 should
不能接受 Matcher[NodeSeq]
并且需要 Matcher[GenSeq[Node]]
.
2 种解决方案
- 替换
NodeSeq
的所有实例至GenSeq[Node]
以便类型在任何地方都匹配。 或者,使用转换函数显式包装 xml。
convertToAnyShouldWrapper(xml).should(matchXML(expected))
关于ScalaTest - 编写自定义匹配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16341868/