使用类型参数写入函数

时间:2016-09-30 12:33:35

标签: scala generics scalatest type-parameter

我有一个单元测试,测试一些解决方案。但是这个测试代码也可以用于测试另一个非常相似的解决方案。我想要做的是测试代码是通用的,可以应用于这两种解决方案,如下所示:

describe("when table contains all correct rows") {
      it("should be empty") {
        def check[T](func: T => List[Row]) = {
          val tableGen = new TableGenerator()
          val table: Vector[Row] = tableGen.randomTable(100)
            .sortWith(_.time isBefore _.time).distinct
          val result: List[Row] = func(table)
          assert(result.isEmpty)
        }

        check(Solution.solution1)
        check(Solution.solution2)
      }
    }

解决方案有类型:

solution1: IndexedSeq[Row] => List[Row]
solution2: Seq[Row] => List[Row]

如何编写 check()函数才能做到这一点? 什么是最好的方法来编写这个(可能以其他方式)消除代码重复?

更新 当我尝试编译此代码时,我在func(table)

中遇到类型不匹配错误
Error:(36, 29) type mismatch;
 found   : table.type (with underlying type scala.collection.immutable.Vector[com.vmalov.tinkoff.Row])
 required: T
          val result = func(table)

2 个答案:

答案 0 :(得分:4)

为此,您需要能够将Vector[Row]传递给func,因此任何Vector[Row]都必须是T;也就是说,TVector[Row]的超类型。您可以使用绑定的类型参数来告诉编译器:

def check[T >: Vector[Row]](func: T => List[Row])

或者,通过上述推理,当T => List[Row]Vector[Row] => List[Row]的超类型时,函数T也将是函数Vector[Row],并且Scala编译器知道这(函数在其参数类型中是逆变)。所以这个签名相当于更简单的

def check(func: Vector[Row] => List[Row])

当然,你可以概括一下,但多少取决于你的具体愿望。例如。您可以将List[Row]替换为Seq[Row](无处不在),或使用类型参数替换,并将额外的函数传递给check

def check[A](func: Vector[Row] => A)(test: A => Boolean) = {
  val table = ...
  val result = func(table)
  assert(test(result))
}

check(Solution.solution1)(_.isEmpty) // the compiler infers A is List[Row] 

答案 1 :(得分:3)

您的情况,也许足以以更具体的方式抽象类型,例如定义您期望Travesable。

  def check[S[_] : Traversable](func: S[Row] => List[Row])

这会接受Seq或IndexedSeq作为有效参数,同时也会限制它。

我希望它有所帮助

编辑:检查Alexey Romanov答案,就像这样,你将无法以你的方式调用func。抱歉,

def check(func:Vector [Row] => List [Row])