其实很简单。你的第一个例子涉及到“泛型”这个概念。
“泛型”的目标很简单,就是让某些方法成为“通用的”,例如不依赖于具体类型。
我们来看一个简单的例子。假设我想写一个针对List
的drop1
方法。
我可以为每种类型都写一个方法(费时、重复):
def drop1(l: List[Int]): List[Int] = l.tail
def drop1(l: List[String]): List[String] = l.tail
你可以看到,你必须为每种类型编写以上内容。为了克服这个问题,你需要使用泛型:
您可以看到,对于每个单独的类型,您都需要编写上述代码。为了解决这个问题,您可以使用泛型:
def drop1[A](l: List[A]): List[A] = l.tail
这段代码的含义是:无论列表中包含什么类型,都给我它的尾部。
为了避免为数量几乎无限的类型编写成千上万个drop1
变体,我只需要编写一个。
在Scala中,你可以使用以下代码实现:
implicit class ListOps[A](val l: List[A]) extends AnyVal {
def drop1: List[A] = l match {
case head :: tail => tail
case Nil => Nil
}
}
List(1, 2, 3).drop1
通常情况下,重命名已知的库方法是不好的做法。tail操作是不安全的,而drop操作是安全的。这样做只会引起混淆,因为默认情况下已有一个drop方法。请勿更改现有的方法名。
List(1, 2, 3) drop 1
[A]
?这只是语法要求吗? - CaballeroInt
的drop1
对其可以执行的操作有更少的保证。例如,它可以查看第五个整数,如果它等于74,则可以删除五个元素而不仅仅是一个。理论上,参数化版本不知道元素的任何信息,只能在列表的结构上进行操作。当然,Scala暴露了JVM的缺陷,如.isInstanceOf
,以解决这个问题,但至少在理论上,参数化的drop1
更加可靠。 - Mysterious Dan