=> Unit) { range foreach (op) } loop(1 to 5){println} // 1 2 3 4 5 loop(1 to 5){x => if (x % 2 == 0) println(x)} // 2 4 还有几 个更为复杂的例子,Actor lib,它是作为扩展被添加到 Scala 这一语言中的,我们将在下文 中对它展开讨论。 不过,Scala 之所以是可扩展的,在于互相关联的两点:它是真正的面向对象的语言和真正 的函数式语言。 面向对象 Scala 中每个事物都是对象(对象的方法除外) ,因此,没有必要对基本(primitive)类型或 引用类型进行区分,这就是所谓的:统一对象模型(Uniform Object Model) 。但是,正如我 之前在优化流程中所提到的,值类型对象被转换为 Java 基本类型,因此不必担心性能的问
题。其内部还包含为类方法分组的单件对象(Singleton object) 。 ◆所有操作都是方法调用,+ - * ! / 都是方法,因此,没有必要进行操作符重载。 ◆非常精细的访问控制,用户可以控制对某些包的某些方法的访问。 ◆Scala 具有 trait,与 Ruby 中的 mixin 类似,就像 Java 中的 interface
s,但实现了某些 它们的方法, 因此, 用户在箱体 (box) 之外拥有富封装器 (wrapper) 和富交互接口 (interface) 。 函数式语言 函数式语言具有很多特点,不过在扩展性这一语境中,我们所关心的是两个事实: ◆函数是第一等级(first-class)的值 这表示用户可以将函数作为值传递, 也可以作为值返回。 这样可以获得简洁而具有可读性的 代码,正如上文中作为示例的过滤代码段。 ◆纯函数(pure function) Scala 支持没有副作用的纯函数, 这意味着: 如果你的输入相同, 那么输出结果也总是相同。 这样能够让代码更为安全,对代码测试也更为方便。 但是,Scala 是通过什么方式来支持纯函数的呢?通过不变性(immutability) :偏向固定的 引用(与 java 中的 final 或其他语言中的 constant 类似)以及具有不变的数据结构,一旦 创建便不可修改。 不变性是拥有纯函数的安全保证,但并不是唯一的方式。没有不变性,你仍然可以编写安全 的代码。 这就是为什么 Scala 不是强制推行不变性而只是鼓励使用它。 最终, 你会发现 Scala 中许多数据结构具有了两种实现方式,一种是可变的,另一种是不可变的,不可变的数据结 构是缺省导入的。 每当提到不变性时, 有人就会开始担心性能的问题, 对于某些情况, 这种担忧并非毫无来由, 但对于 Scala,最终结果却与这一担忧相反。不可变的数据结构相对于可变的数据结构,更 有助于获得较高的效率。 其原因之一在于强大的垃圾收集器 (garbage collector) 与 JVM 中 , 的垃圾收集器类似。 更佳的并行模型 当涉及到线程这一问题时,Scala 支持传统的 shared data 模型。但是,使用这种模型较长 一段时间之后,许多人发现使用这种模型编写代码,非常难以实现以及进行测试。你总是需 要考虑死锁问题和竞争条件。 因此, Scala 提供了另一个称为 Actor 的并行模型, 其中, actor 通过它的收件箱来发送和接收非同步信息, 而不是共享数据。 这种方式被称为: shared nothing 模型。一旦你不再顾虑共享数据的问题,也就不必再为代码同步和死锁问题而头痛。
被发送信息的不变性本质以及 actor 中串行处理,这两者使得对于并行的支持更为简便。 有关 Scala 并行的问题,请参阅这篇文章,对于这个概念你会有更好的理解。 在讲述下一个要点之前,我需要提到这样一个事实,一些人将 Actor 的使用视为编程语言 的一种进化。正如,Java 的出现,将程序员们从指针和内存管理的泥淖中拯救出来一样, Scala 的到来,让程序员们不必再为代码同步以及共享数据模型整天苦思冥想。 静态类型 当我想要讲述这一要点的时候,才
发现,对于静态类型语言的正反两面,我试图给予同样的 关注。事实上,关于这一话题的争论总是没完没了,但我要作出两点总结,而这两点是大多 数人讨论的热点: ◆使用静态类型语言编写的代码更加健壮(robust) TDD 的存在,让许多关于动态类型语言和健壮代码的讨论失去了意义,虽然这是正确的, 当我们仍然不能忽视这样一个事实: 对于动态类型语言, 你需要编写更多的测试代码来检查 类型,而在静态类型语言中,你可以将这些问题交给编译器处理。此外,还有一些人认为, 使用静态类型语言,你的代码将具有更好的自我记录。 ◆使用静态类型语言编写的代码过于严格