4

假设我有一张地图:

val m = Map("foo" -> 10, "bar" -> 5)

我想将其转换为以下格式的字符串(键和值用“:”分隔,不同的元素用“,”分隔):

"bar:5,foo:10"

请注意,键现在已排序。

我如何编写一个函数来一般地执行这种转换?我试过

def f[A, B](m: Map[A, B]): String = {
  m.toList.sortBy(_._1).map { x => x._1 + ":" + x._2 }.mkString(",")
}

但这不起作用,因为我需要以某种方式指定它A是可订购的。我不知道该怎么做——我尝试向Orderer我的函数添加一个隐式参数,但它不起作用。

4

1 回答 1

8

使用Ordering类型类:

def f[A: Ordering, B](m: Map[A, B]): String = {
  m.toList.sortBy(_._1).map { x => x._1 + ":" + x._2 }.mkString(",")
}

f这会使用隐式参数添加另一个参数列表Ordering。方法签名实际上是在幕后翻译成这样的:

def f[A, B](m: Map[A, B])(implicit evidence: Ordering[A]): String

然后该evidence参数被拾取sortBy并用于比较元素。

编辑:

请注意,您不能Ordered以与Ordering. 该Ordered特征旨在与将要排序的对象类型混合在一起(如在 Java 中)。换句话说,A必须扩展Ordered[A],然后您将其写为A <: Ordered[A].

然而,这种继承方法Ordered不如使用类型类方法强大Ordering,因为它不够灵活。如果其他人定义A并且没有决定将其扩展Ordered[A],那么您将无法使用它sortBy(至少在没有创建包装类的情况下不能使用)。另一方面,您始终可以Ordering[A]在范围内声明一个新的隐式而不更改A继承的内容,并Ordering以您喜欢的任何方式实现它。这允许您A在实现者A忘记这样做时定义类型对象的排序方式,并在您想要非默认排序时重新定义它们的排序方式。

于 2012-06-19T07:58:01.677 回答