Scala:为什么我的Scala Test自定义匹配器无法编译?

时间:2016-02-01 00:47:40

标签: scala scala-collections scalatest

我正在从书Learning Scala开始练习,一个问题是:

  

创建一个容器类,其中包含一个实例和一个   参数化类型的实例。构造函数应该采用   可变数量的实例(例如,字符串或整数或任何其他   参数化类型),可以使用vararg参数实现。

我想出了以下内容:

 $scope.lineTotal = function(line){
    var markup = 1 + (line.markupPct / 100);
    var discount = 1 - (line.discountPct / 100);

    var lineTotal = line.price * discount * markup * line.qty;

    $scope.newArray.push(lineTotal);
    return lineTotal;
}

到目前为止,这么好。问题在于测试此代码。使用Scala Test和自定义匹配器的以下测试无法编译,更具体地说是sealed abstract class MyList[A] sealed class MyNil[A] extends MyList[A] sealed case class Cons[A](h: A, t: MyList[A]) extends MyList[A] object MyNil { def apply[A] = new MyNil[A] } object MyList { def apply[A](items: A*): MyList[A] = { items match { case h :: t => Cons[A](h, apply(t: _ *)) case _ => MyNil[A] } } } 方法。你能帮我理解为什么吗?

isEqual

修改1 : 根据请求包含IntelliJ的所有编译错误消息:

class MyListSpec extends FlatSpec with Matchers {
  "MyList" should "be instantiated as expected" in {
    val inputAndOutput = Table(
      ("ip", "op"),
      (Nil, MyNil[Int]),
      (List(1), Cons[Int](1, MyNil[Int])),
      (List(1, 2), Cons[Int](1, Cons[Int](2, MyNil[Int]))),
      (List(1, 2, 3), Cons[Int](1, Cons[Int](2, Cons[Int](3, MyNil[Int]))))
    )

    forAll(inputAndOutput) { (ip, op) =>
      val o = MyList(ip: _ *)
      println(o)

      o should equal(op)
    }
  }

  def equal[Int](right: MyList[Int]) = new MyListMatcher(right)
}

class MyListMatcher[Int, A <: MyList[Int]](val right: A) extends Matcher[A] {
  override def apply(left: A): MatchResult = {
    MatchResult(
      isEqual(left),
      s"""MyList $left did not match "$right"""",
      s"""MyList $left matched "$right""""
    )
  }

  def isEqual[A <: MyList[Int]](left: A) = {
    left match {
      case _: MyNil[Int] if right.isInstanceOf[MyNil[Int]] => println("Both are Nil."); true
      case Cons[Int](h, t) if right.isInstanceOf[Cons[Int]] => {
        println("Both are Cons.")
        left == right
      }
      case _ => println("No match."); false
    }
  }
}

2 个答案:

答案 0 :(得分:1)

回答我自己的问题,以下测试代码有效。问题是在方法Int中不包含Cons类型参数和isEqual案例。

class MyListSpec extends FlatSpec with Matchers {
  "MyList" should "be instantiated as expected" in {
    val inputAndOutput = Table(
      ("ip", "op"),
      (Nil, MyNil[Int]),
      (List(1), Cons[Int](1, MyNil[Int])),
      (List(1, 2), Cons[Int](1, Cons[Int](2, MyNil[Int]))),
      (List(1, 2, 3), Cons[Int](1, Cons[Int](2, Cons[Int](3, MyNil[Int]))))
    )

    forAll(inputAndOutput) { (ip, op) =>
      val o = MyList(ip: _ *)
      println(o)

      o should equal(op)
    }
  }

  def equal(right: MyList[Int]) = new MyListMatcher(right)
}

class MyListMatcher(val right: MyList[Int]) extends Matcher[MyList[Int]] {
  override def apply(left: MyList[Int]): MatchResult = {
    MatchResult(
      isEqual(left, right),
      s"""MyList $left did not match "$right"""",
      s"""MyList $left matched "$right""""
    )
  }

  def isEqual(left: MyList[Int], right: MyList[Int]): Boolean = {
    left match {
      case _: MyNil[Int] if right.isInstanceOf[MyNil[Int]] => println("Both are Nil."); true
      case Cons(h, t) if right.isInstanceOf[Cons[Int]] => {
        println("Both are Cons.")
        val r = right.asInstanceOf[Cons[Int]]

        h == r.h && isEqual(t, r.t)
      }
      case _ => println("No match."); false
    }
  }
}

答案 1 :(得分:1)

您的代码存在问题:

def equal[Int](right: MyList[Int]) = new MyListMatcher(right)

<强> TL; DR

改变这个:

class MyListMatcher[Int, A <: MyList[Int]](val right: A) extends Matcher[A] {

对此:

class MyListMatcher[A <: MyList[Int]](val right: A) extends Matcher[A] {

完整说明

您遇到的问题仅仅是Scala编译器试图找出您的新MyListMatcher实例应该是什么类型的参数。

因为你的MyListMatcher类是一个带有两个参数的类型构造函数(一个是硬编码为Int而另一个是从构造函数参数推断出来的),所以Scala编译器会看到这个并假设第一个参数是没什么,因为它没有在equal方法中指定。

只需删除第一个Int类型参数,您的问题就会消失