我不认为有任何区别,或者有理由更喜欢一个而不是另一个,但想检查一下......
def length(l: List[Any])
def length[T](l: List[T])
我不认为有任何区别,或者有理由更喜欢一个而不是另一个,但想检查一下......
def length(l: List[Any])
def length[T](l: List[T])
你也可以这样写:
def length(l: List[_])
现在,关于您的问题,List[Any]
确实会接受任何问题List
,但如果您尝试过Set[Any]
,它将无法正常工作!例如,尝试将 a 传递Set[Int]
给它:
scala> def length(s: Set[Any]) = s.size
length: (s: Set[Any])Int
scala> val set = Set(1, 2, 3)
set: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
scala> length(set)
<console>:10: error: type mismatch;
found : scala.collection.immutable.Set[Int]
required: Set[Any]
Note: Int <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
length(set)
^
List
是协变的,这使得这成为可能,但并非每个参数化类都是协变的。不过,您的参数化版本或上述版本都可以使用。
我想不出任何理由比另一个更喜欢一个,但我宁愿在不需要时不参数化某些东西。如果不出意外,它将对编译速度产生轻微的积极影响。
如果您只想要 any 的长度List
,那么对您来说没有区别。
但是,如果您想要对该列表中的元素进行操作,那就有。
val l = List(1, 2, 3, 4)
def secondElementAny(l: List[Any]) = l.tail.head
def secondElementGen[A](l : List[A]) = l.tail.head
给出这两个函数和列表,我们期望2
从List
.
val secondAny = secondElementAny(l)
val secondGen = secondElementGen(l)
如果我们将这些值打印到控制台,我们可以发现没有区别,但是如果我们尝试将它们转换Float
为例如,我们将得到一个错误。secondAny.toFloat
会告诉我们, secondAny 是类型Any
,我们不能使用toFloat
on函数Any
。
相比之下secondGen.toFloat
会给我们一个Float
价值。
这样做的原因是,编译器近似于完整的签名如下。
def secondElementAny(l: List[Any]): Any = l.tail.head
def secondElementGen[A](l: List[A]): A = l.tail.head
如您所见,第一个函数的返回类型是Any
,所以我们总是会得到一个Any
,而第二个函数的返回类型取决于List
. 我们将获得该类型的元素。这是类型安全的。
它们是有区别的:
def head_1(l: List[Any]) = {
l.head
}
def head_2[T](l: List[T]) = {
l.head
}
// Doesn't compile, head_1 returns Any
// head_1(List(1,2,3)) > 1
head_2(List(1,2,3)) > 1 //> res0: Boolean = false