【问题标题】:Write function with type parameter使用类型参数编写函数
【发布时间】:2016-09-30 12:33:35
【问题描述】:

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

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)

【问题讨论】:

  • 为什么你认为你需要做任何事情?这个check 函数应该已经能够做到这一点,并且在您显示的内容中没有要消除的重复代码。
  • 一旦我试图编译我得到类型不匹配错误:找到向量[行],需要 T(我传递给 func 的表)。第二个问题是关于可能有另一种更好/更受欢迎的方法来抽象这些东西。
  • 你应该在问题中添加它。
  • 好的,抱歉,错过了一点。
  • 我建议您添加一条消息以帮助识别测试,否则如果测试失败,您将无法很快知道两者中的哪一个。

标签: scala generics scalatest type-parameter


【解决方案1】:

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

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

或者,根据上述推理,函数T => List[Row] 也将是函数Vector[Row] => List[Row],恰好当TVector[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] 

【讨论】:

  • 非常感谢!这正是我想要的。
【解决方案2】:

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

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

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

希望对你有帮助

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

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

【讨论】:

  • 我想你的意思是S[X] <: Traversable[X]
  • 这似乎并没有解决问题,我回答得太快了:P 但 Alexey Romanov 似乎已经很好地回答了这个问题。
  • 感谢您的回复。但实际上,这并不能解决问题。
猜你喜欢
  • 1970-01-01
  • 2018-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-16
  • 1970-01-01
  • 2021-03-23
相关资源
最近更新 更多