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

标签 scala implicit

我正在尝试为一个以 Squants 时间作为参数的类编写 Specs2 测试。诀窍在于,这两个工具都定义了一个隐式,它添加了一个名为“seconds”的方法来将数字转换为它们自己的表示形式(一种情况下是 sqants.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 隐式吗?

最佳答案

方法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 您可以在规范中混合使用特征以避免隐式转换:

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

关于scala - 隐式转换导致无限递归,但这不应该进行类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27906905/

相关文章:

scala - list 与类 list 。这个 Scala 错误是什么意思?

scala - Scala 脚本中未调用 Main 方法

list - 无法推断参数类型

scala - 将 (A => (M[B], M[C])) 转换为 (A => M[(B, C)])

scala - 如何解决 Scala 中重载解析的这种限制?

Scala 和 Java - 隐式参数和继承

scala - 如何使用 SBT 帮助我的库解决传递依赖冲突

scala - 如何覆盖隐式值?

html - 使用隐式宽度和无空格换行防止元素拉伸(stretch)

scala - 如何并行化 Spark scala 计算?