使用类型参数编写函数

Write function with 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)

你的情况,也许足以以更具体的方式抽象类型,比如定义你期待一个 Travesable。

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

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

希望对你有帮助

已编辑:检查 Alexey Romanov Answer,因为这样您将无法按照您的方式调用 func。对此感到抱歉

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

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

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

或者,根据上述推理,当 TVector[Row] 的超类型时,函数 T => List[Row] 也将是函数 Vector[Row] => List[Row],并且 Scala 编译器知道这一点(函数在它们的参数类型中是逆变)。所以这个签名等价于 simple

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]