隐式转换导致无限递归,但不应该进行类型检查

时间:2015-01-12 16:51:43

标签: scala implicit

我正在尝试为一个以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 =>持久隐式吗?

1 个答案:

答案 0 :(得分:3)

方法toSecondsTime 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,其中需要从DurationTime的隐式转换,依此类推。因此,您在运行时获得无限递归调用,这在编译器方面是完全正确的,理论上您可以停止此递归,并且没有通用方法(请参阅halting problem)来检测它。

您可以在规范中混合使用NoTimeConversions特征以避免隐式转换:

  

此特征可用于停用时间转换(以避免   与Akka的转换冲突,例如