使用类型参数编写函数
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
;也就是说,T
是 Vector[Row]
的超类型。您可以使用类型参数绑定将此告诉编译器:
def check[T >: Vector[Row]](func: T => List[Row])
或者,根据上述推理,当 T
是 Vector[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]
我有一个单元测试,测试一些解决方案。但是这个测试代码也可以用于测试另一个非常相似的解决方案。我想要做的是将测试代码通用化以应用于两种解决方案,如下所示:
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
;也就是说,T
是 Vector[Row]
的超类型。您可以使用类型参数绑定将此告诉编译器:
def check[T >: Vector[Row]](func: T => List[Row])
或者,根据上述推理,当 T
是 Vector[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]