【发布时间】:2014-01-14 14:06:22
【问题描述】:
有什么区别
def drop1[A](l: List[A]) = l.tail
和
def drop1(l: List[Int]) = l.tail
只要用法看起来像
drop1(List(1,2,3))
?
什么时候应该使用其中一种,为什么?虽然我可以理解第二个示例,但我并不真正理解第一个示例的目的。
【问题讨论】:
标签: scala types parametric-polymorphism
有什么区别
def drop1[A](l: List[A]) = l.tail
和
def drop1(l: List[Int]) = l.tail
只要用法看起来像
drop1(List(1,2,3))
?
什么时候应该使用其中一种,为什么?虽然我可以理解第二个示例,但我并不真正理解第一个示例的目的。
【问题讨论】:
标签: scala types parametric-polymorphism
真的很简单。您的第一个示例涉及泛型的概念。
泛型有一个简单的目标,使某些方法泛型,例如不依赖于类型。
让我们看看这个简单的例子。假设我想为List 写一个drop1 方法。
我可以为每一种类型写一个:(缓慢,重复):
def drop1(l: List[Int]): List[Int] = l.tail // this only works for Int
def drop1(l: List[String]): List[String] = l.tail // this only works for String
您可以了解如何为每种类型编写上述内容。为了克服这个问题,你有泛型:
def drop1[A](l: List[A]): List[A] = l.tail // this works for any given type.
这实质上是说:无论列表中包含的类型是什么,都给我尾巴。
我不需要为几乎无限的类型编写数千个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
}
}
// you can now have
List(1, 2, 3).drop1
重命名众所周知的库方法通常也是一个坏主意。 tail 操作是不安全的,drop 是安全的。你造成的只是混乱,因为有一个默认的drop 方法。
List(1, 2, 3) drop 1
【讨论】:
[A]?这只是语法要求吗?
drop1 专用于 Int 对其可以做什么的保证较少。例如,它可以查看第五个 int,如果它等于 74,它可以删除五个元素而不是一个。参数化的,理论上,对元素一无所知,只能对列表的结构进行操作。当然,Scala 公开了像 .isInstanceOf 这样的 JVM 缺陷来解决这个问题,但从理论上讲,至少参数 drop1 更值得信赖。
简而言之——一些操作不依赖于特定类型并且可以被抽象化。数苹果和数橙子本质上是相同的操作。如果您要重用算法,那么将某些类型抽象出来而不是编写会更聪明
def countOranges(xs: List[Orange]) = { some code }
def countApples(xs: List[Apple]) = { the very same code }
【讨论】:
我有点晚了,如果你对 Java 中的泛型有一个想法,那么可以在这里进行类比:-
Java --> 泛型类的对象可以传入方法参数。
class Test<T> {
// An object of type T is declared
T obj;
Test(T obj) { this.obj = obj; } // constructor
// some other methods in class
}
Test<String> testobj = new Test<String>();
public void function(testobj){
// do something with testobj
}
Scala --> 与通用参数函数在 scala 中的工作方式相同。这里,[A] 定义了 scala 中的泛型类型
def drop1[A](l: List[A]) = l.tail
上述函数的用法:-
scala>drop1(List(1,2,3)) // output List(2, 3)
scala>drop1(List(1.0,2.0,3.0)) // output List(2.0, 3.0)
scala>drop1(List('a','b','c')) // output List(b, c)
说明:- 只需传递任何类型的列表,它就像一个魅力。语法如下:-
def function[Type](param:Type):Type = {do something}
【讨论】:
//snippet to explain scala parametric polymorphism
object MethodParametricPolymorphism {
//parametric polymorphism is similar/same as of java generics
def countOranges(oranges : List[Orange]) = oranges.size;
def countApples(apples : List[Apple]) = apples.size
//if algo is same then paramatric polymorphism can be used
def count[A](items : List[A]) = items.size
val oranges : List[Orange] = List( new Orange(1.1))
val apples : List[Apple] = List( new Apple(2.1), new Apple(2.2))
countOranges(oranges);
countApples(apples);
//using polymorphic typed method
count(oranges);
count(apples);
case class Orange ( weight: Double)
case class Apple ( weight: Double)
}
【讨论】: