带有Ordering和ClassTag的scala多态类型签名

时间:2018-04-25 20:13:17

标签: scala types polymorphism

我需要帮助理解这种类型的签名:

def func[A : Ordering : ClassTag](a: A) = ???

我已经使用上面的类型签名得到了虚拟示例...以及我更熟悉的类型签名,我相信基于我的虚拟示例接近同样的东西,但我可以还提出了一个玩具示例,它们显然不一样。

这两个看似相似:

import scala.reflect.ClassTag

// type signature in question
def func1[A : Ordering : ClassTag](elems: A*) = 
  Array[A](elems: _*).sorted

// my typical type signature
def func2[A <% Ordered[A]](elems: A*)(implicit c: ClassTag[A]) = 
  Array[A](elems: _*).sorted

使用示例:

class BB(val i: Int) extends Ordered[BB] {
  def compare(that: BB): Int = that.i - i
  override def toString = s"BB(${i})"
}

func1(new BB(33), new BB(100), new BB(-1))
func2(new BB(33), new BB(100), new BB(-1))

每个的输出是:

Array[BB] = Array(BB(100), BB(33), BB(-1))

一个边缘的情况我可以想出它们不同的地方......表明一个不仅仅是另一个的语法糖...是以下,其中函数有一个隐含的顺序,类不同于类的自然排序。

这个例子(如下)工作正常,implicit val ordering覆盖了BB类的自然排序顺序,就像我预期的那样。

def func3[A <% Ordered[A] : ClassTag](elems: A*) = {
  // opposite order defined in class BB
  implicit val ordering: Ordering[A] = 
    Ordering.by{ case bb: BB => bb.i }  

  Array[A](elems: _*).sorted
}

这个版本(下面)给我一个错误......

def func3[A : Ordering : ClassTag](elems: A*) = {
  // opposite order defined in class BB
  implicit val ordering: Ordering[A] = 
    Ordering.by{ case bb: BB => bb.i }  

  Array[A](elems: _*).sorted
}
  

错误:含糊不清的隐含值:两个值证据$ 1类型订购[A]   和订购[A]类型的值排序匹配预期类型   scala.math.Ordering [A]

所以基于此...我猜: OrderingOrdered[BB]转换为implicit val ordering ......或类似的东西?我的玩具示例是否有更深层次的差异无法揭示?

提前致谢。

1 个答案:

答案 0 :(得分:1)

在类型参数之后的:是用于声明隐式参数的语法糖。在这种情况下,这意味着

def func1[A: Ordering: ClassTag](elems: A*) = Array[A](elems: _*).sorted

相同
def func1[A](elems: A*)(implicit ordering: Ordering[A], classTag: ClassTag[A]) = Array[A](elems: _*).sorted

另一方面,func2声明从<%A的视图范围(Ordered)。知道了这一点,编译器可以召唤传递给Ordering[Ordered]方法的sorted

最新版本的fun3未编译的原因是因为您在范围中提供了2个隐式Ordering[A]:声明为隐式参数fun3的隐式参数和隐式参数val ordering。编译器不知道选择哪一个并且它抱怨它,你应该删除其中一个来修复它。

无论如何,在这些函数的实现中引入有关特定类型的代码并不是一个好主意。对于任何不是ordering的类型,在创建val BB时的模式匹配将失败。

如果您的目标是定义特定的Ordering[BB],您可以在BB的伴随对象中执行此操作,然后将其加载到调用函数的隐式作用域中,如下所示

class BB(val i: Int) {
  override def toString: String = s"BB(${i})"
}

object BB {
  implicit val ordering = Ordering.by[BB, Int](_.i)
  val reverseOrdering = Ordering.by[BB, Int](-_.i)
}

然后,当您尝试订购BB时,它会默认选择隐式排序,但您可以通过执行

来覆盖它。
implicit val ord = BB.reverseOrdering
Seq[BB]().sorted