如何在Scala中提供通用方法的专业实现?

时间:2017-01-31 09:46:28

标签: scala generics mockito

我正在使用Slick 2.1.0的包装类开发一个现有的代码库(我知道)。这个包装器有一个名为transaction的方法,它是一个通用的 - 它需要一个(f: => T)(所以它是通过名称传递)。我需要模拟这个类进行单元测试。我们也在使用Mockito 1.10.19(我知道),这不会让我嘲笑一个名字(我相信......)。所以我不得不实现构建这个包装类的底层特征。

当前的问题是:我想模仿这个transaction方法,所以它什么都不做。我正在测试的代码在(f: => Unit)中传递。所以我想实现这个方法来返回Future.Done。 (我是否提到过我们使用的是Finagle而不是Scala期货?)但这种方法是通用的。我该如何正确专业化?

这是我目前的尝试:

val mockDBM = new DatabaseManager {
    override def transaction[@specialized(Unit) T](f: => T): Future[T] = Future.value(f)
    def transaction(f: => Unit): Future[Unit] = Future.Done
}

当然,编译时出现have same type after erasure错误。显然我不知道@specialized是如何运作的。

我该怎么办?也许我毕竟可以使用Mockito?或者我需要了解泛型方法的实际特征是什么?

我发现了这个,可能包含了答案,但我在FP中没有正式的背景,我根本不理解这一点:How can one provide manually specialized implementations with Scala specialization?

1 个答案:

答案 0 :(得分:2)

@specialized不允许您提供专业化,它只是生成自己的专业化。链接问题中提供的答案需要更改签名。从问题来看,你似乎无法改变它,在这种情况下,你运气不好。如果你可以......你可能仍然不幸,这取决于这个代码的确切调用方式。

OTOH,"我想忽略f的解决方案,但如果通用属于Future.Done类型,则只能返回Unit"更简单:

class Default[A] {
  var x: A = _
}
object Default {
  def apply[A]() = (new Default[A]).x
}

val mockDBM = new DatabaseManager {
  override def transaction[T](f: => T): Future[T] = {
    Future.value(Default(x))
  }
}

假设你需要一个成功的未来,但不关心价值,那就是;如果你只需要任何的未来,override def transaction[T](f: => T): Future[T] = Future.???