Scala 编译器通常可以推断表达式的类型,因此你不必显式声明它。
省略类型
val businessName = "Montreux Jazz Café"
编译器可以检测到 businessName
是一个字符串。它对方法的工作方式类似
def squareOf(x: Int) = x * x
编译器可以推断出返回类型是 Int
,因此不需要显式的返回类型。
对于递归方法,编译器无法推断结果类型。这是一个程序,它将因此导致编译器失败
def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
def fac(n: Int) = if n == 0 then 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
的参数类型来确定 A
和 B
的类型。同样适用于 x
的类型。
参数
编译器从不推断方法参数类型。但是,在某些情况下,当函数作为参数传递时,它可以推断匿名函数参数类型。
Seq(1, 3, 4).map(x => x * 2) // List(2, 6, 8)
映射的参数是 f: A => B
。因为我们在 Seq
中放置了整数,所以编译器知道 A
是 Int
(即 x
是一个整数)。因此,编译器可以从 x * 2
推断出 B
是类型 Int
。
不 依赖类型推断的情况
通常认为在公开 API 中声明公开成员的类型更具可读性。因此,我们建议你为将公开给代码用户的任何 API 明确指定类型。
此外,类型推断有时会推断出过于具体的类型。假设我们编写
var obj = null
然后我们无法继续进行此重新赋值
obj = new AnyRef
它不会编译,因为为 obj
推断的类型是 Null
。由于该类型的唯一值是 null
,因此无法分配不同的值。