7

在为 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))

任何想法这意味着什么?

4

2 回答 2

8

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

类型检查器的工作方式如下。

xml.should(matchXML(expected))
  • 因为该方法should不是 a 的一部分NodeSeq,所以编译器会尝试查找到 a的隐式转换。《Programming in Scala》一书规定,这种隐式转换应该是最具体的:xmlShouldMatcher

“到 Scala 2.7 为止,这就是故事的结局。每当应用多个隐式转换时,编译器都会拒绝在它们之间进行选择。...... Scala 2.8 放宽了这条规则。如果一个可用的转换严格来说比其他的更具体,那么编译器将选择更具体的那个。......如果以下情况之一适用,则一个隐式转换比另一个更具体:前者的参数类型是后者的子类型......”

  • 因为NodeSeqextends Seq[Node],所以下面的函数

    convertToSeqShouldWrapper[T](o : scala.GenSeq[T]) : SeqShouldWrapper[T]

    因此,它是所有其他方法中最具体的一种。

程序改写为:

`convertToSeqShouldWrapper(xml).should(matchXML(expected))`

whereconvertToSeqShouldWrapper(xml)SeqShouldWrapper[T]where T = GenSeq[Node]

shouldfrom方法SeqShouldWrapper接受 aMatcher[T]类型的函数T => MatchResult。因此,它接受一个Matcher[GenSeq[Node]].

因为T出现在箭头的左侧,所以匹配器在 中不是协变T,而是逆变的。ANodeSeq是 a GenSeq[Node],所以 aMatcher[GenSeq[Node]]是 a Matcher[NodeSeq],而不是相反。这解释了上述错误,其中方法should不能接受 aMatcher[NodeSeq]并且需要 a Matcher[GenSeq[Node]]

2 解决方案

  • NodeSeq替换to的所有实例,GenSeq[Node]以便类型在任何地方都匹配。
  • 或者,使用转换函数显式包装 xml。

    convertToAnyShouldWrapper(xml).should(matchXML(expected))

于 2013-05-06T09:23:47.297 回答
-1

在我看来,您的matchXML方法不在范围内。

于 2013-05-03T16:24:48.460 回答