隐式使用Scala的Predef时如何防止堆栈溢出
鉴于这个简单的代码片段,我很惊讶地激起了堆栈溢出的简单过程:
Given this simple code snippet I am astounded to provoke a stack overflow this easy:
implicit def foobar: Unit = implicitly[Unit]
在更复杂的用例中,我有以下情形:
In my little more complex use case I have the following situtation:
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]]
}
在类Foo
中定义方法repr2Ordered
无效,因为类型Repr_Tpe
是抽象的.因此,我决定复制&粘贴声明并从中进行定义; 显然从上面导致堆栈溢出.只有从类Bar
中的定义中删除修饰符implicit
才能解决此问题.
Defining method repr2Ordered
in class Foo
does not work because type Repr_Tpe
is abstract. So I decided to copy & paste the declaration and make a definition out of it; apparently leading to the stack overflow from above. Only by removing the modifier implicit
from the definition in class Bar
solves this problem.
难道没有一个巧妙的解决方案可以避免这种陷阱吗?
Isn't there an elegant solution circumventing this pitfall?
您已将foobar
定义为 be 类型为Unit
的隐式值.然后,将其定义为 类型为Unit
的隐式值.这样想:
You've defined foobar
to be the implicit value of type Unit
. Then you've defined it as the implicit value of type Unit
. Thinking of it this way:
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
与下面的语句相比,您不会感到惊讶的是,这会引起堆栈溢出:
You should be no more surprised that this causes a stack overflow than you would be by this statement:
def tharSheBlows: Unit = tharSheBlows
For something with a bit more elegance, I would use a view bound to ensure that the type paramater is Ordered
instead.
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