如何在使用Scala的Predef.implicitly时防止堆栈溢出

时间:2012-02-25 19:00:24

标签: scala stack-overflow implicit-conversion

鉴于这个简单的代码片段,我很惊讶地发现堆栈溢出很容易:

implicit def foobar: Unit = implicitly[Unit]

在我更复杂的用例中,我有以下情况:

abstract class Foo {
  type Repr_Tpe
  protected implicit def repr2Ordered: Repr_Tpe => Ordered[Repr_Tpe]
}

class Bar extends Foo {
  type Repr_Tpe = Long
  protected implicit def repr2Ordered = implicitly[Repr_Tpe => Ordered[Repr_Tpe]]
}

在类repr2Ordered中定义方法Foo不起作用,因为类型Repr_Tpe是抽象的。所以我决定复制&粘贴声明并从中做出定义; 显然导致堆栈溢出。只有从类implicit中的定义中删除修饰符Bar才能解决此问题。

是不是有一个优雅的解决方案来规避这个陷阱?

1 个答案:

答案 0 :(得分:0)

您已将foobar定义为 类型Unit的隐含值。然后,您已将定义为类型为Unit的隐式值。用这种方式思考:

implicit def foobar: Unit = implicitly[Unit]
// you've defined foobar as the implicit value for Unit.
// so implicitly[Unit] is the same as calling foobar
// which is the same as:
implicit def foobar: Unit = foobar

你应该不会感到惊讶,这会导致堆栈溢出,而不是这个声明:

def tharSheBlows: Unit = tharSheBlows

对于更优雅的东西,我会使用view bound来确保类型参数为Ordered

scala> abstract class Foo[Repr_Tpe <% Ordered[Repr_Tpe]] {}
defined class Foo

scala> class Bar extends Foo[Long] {}
defined class Bar

scala> case class Unordered(data: String)
defined class Unordered

scala> class Bam extends Foo[Unordered] {}
<console>:10: error: No implicit view available from Unordered => Ordered[Unordered].
       class Bam extends Foo[Unordered] {}
                 ^

scala> implicit def bringOrder(u: Unordered) = new Ordered[Unordered] { def compare(that: Unordered) = u.data.compareTo(that.data) }
bringOrder: (u: Unordered)java.lang.Object with Ordered[Unordered]

scala> class Bam extends Foo[Unordered] {}
defined class Bam