Scala:为什么函数需要前面的类型变量?

时间:2013-12-10 23:24:52

标签: scala type-variables

通过first problem of the 99 Scala Puzzles工作,我定义了我自己的last版本,如下所示:

def last[A](xs: List[A]): A = xs match {
  case x :: Nil => x
  case x :: xs => last(xs)
}

我的问题是:为什么last必须直接跟随类型变量,如last[A]?如果我像这样编写函数,为什么编译器不能做正确的事情:

def last(xs: List[A]): A
    .....

(将[A]移到last[A]的末尾?)

如果编译器能够搞清楚,那么以这种方式设计语言的理由是什么?

3 个答案:

答案 0 :(得分:1)

A出现3次:

  1. last[A]

  2. List[A]

  3. : A(在参数列表之后)

  4. 需要第二个指定List包含A类型的对象。需要第3个指定函数返回类型为A的对象。

    第一个是您实际声明A的地方,因此可以在其他两个地方使用。

答案 1 :(得分:1)

您需要撰写last[A],因为A不存在。由于它不存在,通过在函数名称之后声明它,您实际上有机会为此类型定义一些期望或约束。

例如:last[A <: Int]强制执行以下事实:A必须是Int的子类型

声明后,您可以使用它来定义参数类型和返回类型。

答案 2 :(得分:1)

我从@ Lee的评论中得到了一个见解:

  

编译器如何知道列表[A]中的A不引用   实际类型叫A?

为了证明这是有道理的,我尝试用实际类型A的名称替换类型变量String,然后传递函数a List[Int],当last被声明为def last[String](xs: List[String]): String时,我能够通过last一个List[Int]

scala> def last[String](xs: List[String]): String = xs match {
     | case x :: Nil => x
     | case x :: xs => last(xs)
     | }
last: [String](xs: List[String])String

scala> last(List(1,2,3,4))
res7: Int = 4

因此,证明标识符String的行为类似于类型变量,并且不引用具体类型String

如果编译器只是假设不在范围内的任何标识符是类型变量,那么它也会使调试变得更加困难。因此,必须在函数定义的开头声明它。