在 Scala 中可以有Multiple Parameters Lists。您的调用仅传递一个参数。
该方法被声明为def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T],所以第一个参数是(T, T) => Boolean类型的,它是一个接受两个T类型参数并返回一个Boolean值的函数。你传递了一个List[Int],这让 Scala 抱怨。
你为什么想要这样一个你可能会问的东西。好吧,考虑下面的例子。
val stringSorter = msort[String]((a, b) => a.compareTo(b) < 0) _
// stringSorter: List[String] => List[String] = <function1>
val integerSorter = msort[Int]((a, b) => a < b) _
// integerSorter: List[Int] => List[Int] = <function1>
这两个调用创建了两个新函数,它们只接受一个参数 - 您要排序的列表。您不必告诉它如何比较元素,因为您已经这样做了。请注意,您可以使用不同的列表作为参数调用相同的函数。
integerSorter(List(2, 3, 1))
// res0: List[Int] = List(1, 2, 3)
integerSorter(List(2, 4, 1))
// res1: List[Int] = List(1, 2, 4)
stringSorter(List("b", "a", "c"))
res3: List[String] = List(a, b, c)
另请注意,新创建的函数是类型安全的,以下代码将失败:
integerSorter(List("b", "a", "c"))
<console>:10: error: type mismatch;
found : String("b")
required: Int
integerSorter(List("b", "a", "c"))
隐式参数
正如链接中的文章提到的那样,您可能要使用多个参数列表的原因之一是隐式参数。
当使用隐式参数并且你使用了implicit关键字时,它
适用于整个参数列表。因此,如果你只想要一些
参数是隐式的,你必须使用多个参数列表。
让我们稍微修改一下你给我们的示例代码以引入一个新类型:
trait Comparator[T] {
def less(a: T, b: T): Boolean
}
让我们交换参数列表,并在第二个参数列表中添加implicit关键字,所以现在它变成了:
def msort[T](xs: List[T])(implicit c: Comparator[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (c.less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(ys)(c), msort(zs)(c), Nil).reverse
}
}
现在您可以声明隐式对象,以防您不提供时使用,例如
implicit val intComparator = new Comparator[Int] { def less(a: Int, b: Int) = a < b }
msort(List(5, 3, 1, 3))
// res8: List[Int] = List(1, 3, 3, 5)
虽然这似乎不是很吸引人,但它在设计 API 时为您提供了额外的灵活性。假设我们有一个名为CustomType 的类型。它可以在伴生对象中声明一个隐式,它会被编译器“自动”解析。
case class CustomType(ordinal: Int, name: String)
object CustomType {
implicit val customTypeComparator = new Comparator[CustomType] {
def less(a: CustomType, b: CustomType) = a.ordinal < b.ordinal
}
}
msort(List(CustomType(2, "Second"), CustomType(1, "First")))
// res11: List[CustomType] = List(CustomType(1,First), CustomType(2,Second))