是否有任何差异或理由更喜欢这些功能签名之一?

时间:2013-08-13 02:02:13

标签: scala types type-signature

我认为没有任何区别,或者有理由偏爱另一个,但想要检查......

def length(l: List[Any])
def length[T](l: List[T])

3 个答案:

答案 0 :(得分:6)

您也可以这样写:

def length(l: List[_])

现在,关于您的问题,List[Any]确实会接受任何List,但如果您尝试过Set[Any],则无效!例如,尝试将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是共变体,这使得这成为可能,但不是每个参数化类都是协变的。不过,您的参数化版本或上述版本都可以使用。

我想不出有什么理由偏爱另一个,但我不想在不需要的时候参数化。如果不出意外,它将对编译速度产生轻微的积极影响。

答案 1 :(得分:2)

如果您只想要任何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上使用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,而第二个函数的返回类型取决于{{1}的类型}。我们将获得该类型的元素。这是类型安全的。

答案 2 :(得分:0)

有区别:

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