这里我们转载Twitter的Scala课堂 ,转载的内容基本来自Twitter的Scala课堂中文翻译,部分有小改动.
什么是静态类型?它们为什么有用?
按Pierce的话讲:“类型系统是一个语法方法,它们根据程序计算的值的种类对程序短语进行分类,通过分类结果错误行为进行自动检查。”
类型允许你表示函数的定义域和值域。例如,从数学角度看这个定义:
f: R -> N
它告诉我们函数“f”是从实数集到自然数集的映射。
抽象地说,这就是 具体 类型的准确定义。类型系统给我们提供了一些更强大的方式来表达这些集合。
鉴于这些注释,编译器可以 静态地 (在编译时)验证程序是 合理 的。也就是说,如果值(在运行时)不符合程序规定的约束,编译将失败。
一般说来,类型检查只能保证 不合理 的程序不能编译通过。它不能保证每一个合理的程序都 可以 编译通过。
随着类型系统表达能力的提高,我们可以生产更可靠的代码,因为它能够在我们运行程序之前验证程序的不变性(当然是发现类型本身的模型bug!)。学术界一直很努力地提高类型系统的表现力,包括值依赖(value-dependent)类型!
需要注意的是,所有的类型信息会在编译时被删去,因为它已不再需要。这就是所谓的擦除。
Scala中的类型
Scala强大的类型系统拥有非常丰富的表现力。其主要特性有:
参数化多态性 粗略地说,就是泛型编程
(局部)类型推断 粗略地说,就是为什么你不需要这样写代码val i: Int = 12: Int
存在量化 粗略地说,为一些没有名称的类型进行定义
视窗 我们将下周学习这些;粗略地说,就是将一种类型的值“强制转换”为另一种类型
参数化多态性
多态性是在不影响静态类型丰富性的前提下,用来(给不同类型的值)编写通用代码的。
例如,如果没有参数化多态性,一个通用的列表数据结构总是看起来像这样(事实上,它看起来很像使用泛型前的Java):
scala> 2 :: 1 :: "bar" :: "foo" :: Nil res5: List[Any] = List(2, 1, bar, foo)
现在我们无法恢复其中成员的任何类型信息。
scala> res0.head res2: Any = 2
所以我们的应用程序将会退化为一系列类型转换(“asInstanceOf[]”),并且会缺乏类型安全的保障(因为这些都是动态的)。
多态性是通过指定 类型变量 实现的。
scala> def drop1[A](l: List[A]) = l.tail drop1: [A](l: List[A])List[A] scala> drop1(List(1,2,3)) res3: List[Int] = List(2, 3)
Scala有秩1多态性
粗略地说,这意味着在Scala中,有一些你想表达的类型概念“过于泛化”以至于编译器无法理解。假设你有一个函数
def toList[A](a: A) = List(a)
你希望继续泛型地使用它:
def foo[A, B](f: A => List[A], b: B) = f(b)
<console>:7: error: type mismatch; found : b.type (with underlying type B) required: A def foo[A, B](f: A => List[A], b: B) = f(b)
这段代码不能编译,因为所有的类型变量只有在调用上下文中才被固定。即使你“钉住”了类型B:
scala> def foo[A](f: A => List[A], i: Int) = f(i) <console>:7: error: type mismatch; found : i.type (with underlying type Int) required: A def foo[A](f: A => List[A], i: Int) = f(i)
类型推断
静态类型的一个传统反对意见是,它有大量的语法开销。Scala通过 类型推断 来缓解这个问题。
在函数式编程语言中,类型推断的经典方法是 Hindley Milner算法,它最早是实现在ML中的。
Scala类型推断系统的实现稍有不同,但本质类似:推断约束,并试图统一类型。
在Scala中所有类型推断是 局部的 。Scala一次分析一个表达式。例如:
scala> def id[T](x: T) = x id: [T](x: T)T scala> val x = id(322) x: Int = 322 scala> val x = id("hey") x: String = hey scala> val x = id(Array(1,2,3,4)) x: Array[Int] = Array(1, 2, 3, 4)
类型信息都保存完好,Scala编译器为我们进行了类型推断。请注意我们并不需要明确指定返回类型。