如何最低限度地调和 Scala 的 @specialized 和 java.lang.Comparable?

How to minimally reconcile Scala's @specialized and java.lang.Comparable?

我有第三方 Java API 使用这样的方法(简化):

public <C extends Comparable<C>> C jFoo(C c);

我想写一个这样的包装器:

def foo[C <: Comparable[C]](c: C): C = jFoo(c)

为了允许包装器方法接受原语(因为据我所知,无论如何都会发生装箱,所以这不相关),我想专门化 C:

def foo[@specialized(Int, Double) C <: Comparable[C]](c: C): C = jFoo(c)

但是,scalac 抱怨说,由于参数的上限,该方法无法专门化。

一个解决方案是添加一个证据参数:

def foo[@specialized(Int, Double) C, CC <: Comparable[CC]](c: C)
                                                 (implicit evComp: C => CC): CC =
    jFoo(evComp(c))

这有效,您现在可以调用:

foo(2.0)

但是,方法签名 - API 的一部分 - 现在并不是真正可读的。

在方法级别是否有替代方法可以产生等效的、更具可读性的签名,同时保持专业化?

(Scala 2.12.x 很好,Dotty 没那么多)

您可以通过使第二个类型参数 CC 成为特殊 EvC 类型 class.

的类型成员来摆脱它

以下作品:

import java.lang.Comparable

def jFoo[C <: Comparable[C]](c: C): Unit = println("compiles => ship it")

trait EvC[C] {
  type CC <: Comparable[CC]
  def apply(c: C): CC
}

def foo[@specialized(Int, Double) C](c: C)(implicit evC: EvC[C]): Unit = 
  jFoo[evC.CC](evC(c))

implicit object DoubleEvC extends EvC[Double] {
  type CC = java.lang.Double
  def apply(c: Double) = (c: java.lang.Double)
}

foo(42.0) // compiles => ship it

在某种意义上,我只是将 C => CC 部分与类型参数 CC 本身粘合在一起,因此类型 CC 不再出现在类型参数中列表。我不确定你是否可以完全摆脱所有这些,内置原始类型没有实现 java.lang.Comparable.

仍然是事实