我正在尝试为一个以Squants Time作为参数的类编写Specs2测试。诀窍是两个工具都定义了一个隐式,它添加了一个名为“秒”的方法,将一个数字转换成它们自己的表示形式(一个案例中为squants.time.Seconds,另一个案例中为org.specs2.time.Duration),不幸的是,错误的似乎优先。
val a = new MyClass(10 seconds) // doesn't build because MyClass wants a Time instead of a Duration
要说清楚,我可以通过不依赖于暗示来构建Squants时间来解决这个问题,这不是问题。
我更喜欢暗示所以我决定添加一个隐式转换持续时间到时间:
implicit def specsTimeToSquantsTime(t: org.specs2.time.Duration): squants.time.Time = squants.time.Seconds(t.toSeconds)
这让它得到了类型检查,但是当我运行测试时,我得到了一个堆栈溢出并且堆栈跟踪没有多大意义,它说我的隐式转换是在调用自己(这不会出现类似问题,鉴于以上代码,它仍然是不可能的!):
[error] package.TestConversions$.specsTimeToSquantsTime(TestConversions.scala:9)
[error] package.TestConversions$.specsTimeToSquantsTime(TestConversions.scala:9)
[error] package.TestConversions$.specsTimeToSquantsTime(TestConversions.scala:9)
...
所以我有三个问题:这里发生了什么?有一个更好的方法吗?我可以手动隐藏Int =>持久隐式吗?
答案 0 :(得分:3)
方法toSeconds
在Time
class:
final class Time private (val value: Double) extends Quantity[Time] {
...
def toSeconds = to(Seconds)
...
}
https://github.com/garyKeorkunian/squants/blob/master/src/main/scala/squants/time/Time.scala
因此,当编译器看到在Duration
上调用此方法时 - 它正在搜索适当的隐式及其specsTimeToSquantsTime
,其中包含Duration.toSeconds
,其中需要从Duration
到Time
的隐式转换,依此类推。因此,您在运行时获得无限递归调用,这在编译器方面是完全正确的,理论上您可以停止此递归,并且没有通用方法(请参阅halting problem)来检测它。
您可以在规范中混合使用NoTimeConversions
特征以避免隐式转换:
此特征可用于停用时间转换(以避免 与Akka的转换冲突,例如