Scala之旅-多态方法(POLYMORPHIC METHODS)和类型推断(TYPE INFERENCE)

多态方法(POLYMORPHIC METHODS)

Scala 中的方法可以通过类型和值进行参数化。语法和泛型类类似。类型参数用方括号[]括起来,而值参数用圆括号()括起来。

看下面例子:

def listOfDuplicates[A](x: A, length: Int): List[A] = {
  if (length < 1)
    Nil
  else
    x :: listOfDuplicates(x, length - 1)
}
println(listOfDuplicates[Int](3, 4))  // List(3, 3, 3, 3)
println(listOfDuplicates("La", 8))  // List(La, La, La, La, La, La, La, La)

这里写图片描述
这里写图片描述
方法 listOfDuplicates 采用类型参数 A 和值参数 xlength。值 x 是类型 A。如果 length < 1,我们返回一个空列表。否则我们将 x 添加到递归调用返回的重复列表中。(注意符号 :: 指将左边的元素添加到右边的列表)

例子中第一次调用方法时,我们明确提供了类型参数为 [Int]。因此第一个参数肯定是 Int 且返回类型为 List[Int]

第二次调用表明你不必每次都需要提供明确地参数类型。编译器通常可以依据上下文或值参数类型来推断出类型。在这个例中,"La" 是一个 String 类型,因此编译器知道 A 必须是 String

类型推断(TYPE INFERENCE)

Scala 编译器通常可以推断出表达式的类型,因此你不必明确地声明它。

省略类型

val businessName = "Montreux Jazz Cafe"

编译器可以发现 businessNameString 类型。它的工作原理和方法类似:

def squareOf(x: Int) = x * x

编译器可以推断出方法的返回类型为 Int,因此不需要明确地声明返回类型。

对于递归方法,编译器无法推断出结果类型。下面是由于这样的原因而编译失败的程序:

def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)

当调用多态方法或实例化泛型类时,没必要明确参数类型。Scala 编译器将会根据上下文和实际方法的类型/构造器参数推断出缺失的类型参数。

看下面两个例子:

case class MyPair[A, B](x: A, y: B);
val p = MyPair(1, "scala") // type: MyPair[Int, String]

def id[T](x: T) = x
val q = id(1)              // type: Int

编译器使用 MyPair 参数类型推断出 AB 的类型。同样地方式可以推断出 x 的类型。

参数

编译器从不推断方法参数类型。但是,在某些情况下,当函数作为参数传递时,它可以推断出匿名函数的参数类型。

Seq(1, 3, 4).map(x => x * 2)  // List(2, 6, 8)

map 的参数是 f: A => B。因为我们把整数放在了 Seq 里,所以编译器知道 AInt 类型(即 x 是一个整数)。
因此,编译器可以根据 x*2 推断出 BInt 类型。

何时不依赖类型推断

一般认为在公共 API 中声明成员的类型是更具有可读性的。因此,我们建议你为那些将要暴露给用户的任何 API 提供明确地类型。

同时,类型推断有时可能推断出一个太特定的类型。假设我们这样写:

var obj = null

那么我们就不可以继续进行重新分配:

obj = new AnyRef

它不会通过编译,因为类型推断出 obj 的类型是 Null。由于该类型的唯一值是 null,因此不可能再给它分配不同的值。

阅读更多

没有更多推荐了,返回首页