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

Implicit conversions causing infinite recursion, but that shouldn't typecheck

我正在尝试为 class 编写 Specs2 测试,该测试将 Squants Time 作为参数。诀窍在于,这两个工具都定义了一个隐式,它添加了一个名为 "seconds" 的方法来将数字转换为它们自己的表示形式(一种情况下为 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 Time 来解决这个问题,这不是问题所在。

我更喜欢隐式,所以我决定添加一个隐式来将持续时间转换为时间:

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=>Duration 吗?

方法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 特征以避免隐式转换:

This trait can be used to deactivate the time conversions (to avoid conflicts with Akka's conversions for example