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

时间:2018-05-16 12:36:56

标签: scala 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没那么多)

1 个答案:

答案 0 :(得分:2)

您可以通过使其成为特殊CC类型类的类型成员来摆脱第二个类型参数EvC

以下作品:

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仍然是事实。