scala编程 完整中文版 pdf
分享到:
Scala编程 pdf是一本非常通俗易懂的编程学习书籍。对于这种新兴编程语言,这本书详细的讲解了Scala编程的方方面面。不仅有利于新手的学习,而且更多的是一种新的编程思维体系的介绍。每个章节都有不同的侧重,大家可以一一品读。它把面向对象和函数式编程概念有机地结合为整体,循序渐进,由浅入深,经作者精心组织、仔细编排,将语言中的各种概念自然地铺陈在字里行间。除此之外,本书还包含了大量富有针对性和趣味性的示例,它们除了提供对语言各个方面的具体演示之外,还从侧面说明了如何将函数式编程的理念切实并广泛地应用到面向对象编程中。对于有一定编程经验的开发人员,也能够开拓眼界,并致力于提高在软件开发各方面的技能。所以,想领略最新的编程思维,就看这本编程书籍吧!
Lex Spoon是Google的软件工程师。他以EPFL博士后身份在Scala方面工作了两年时间,从佐治亚理工学院(Georgia Tech)获得计算机科学的博士学位。那时他的主要工作是动态语言的静态分析。除了Scala之外,他还从事大量其他的编程语言工作,范围从动态语言Smalltalk到科学性语言X10。他和他的妻子,两只猫、一条吉娃娃还有一只乌龟,现生活于亚特兰大。
Bill Venners是Artima的总裁,兼Artima开发者网站(www.artima.com)的发行人。他是《深入Java虚拟机》(“Inside the Java Virtual Machine”)的作者,该书是定向为程序员的Java平台架构和内部组织的总体研究。他在JavaWorld杂志上有很受欢迎的专栏,内容涵盖Java内部机制,面向对象设计,还有Jini。Bill从Jini诞生伊始就活跃于Jini社区,他曾领导Jini社区的ServiceUI项目,而其中的ServiceUI API已经变成了联系用户界面和Jini服务之间的事实标准。Bill还是ScalaTest(Scala和Java开发的开源测试工具)的首席开发者(lead developer)和设计者。
图示清单 xvii
表格清单 xix
代码清单 xxi
序 I
致谢 III
简介 V
第1章 可伸展的语言 3
1.1 与你一同成长的语言 3
1.2 是什么让Scala具有可扩展性? 6
1.3 为什么选择Scala? 8
1.4 Scala的根源 13
1.5 小结 14
第2章 Scala入门初探 15
2.1 第一步 学习使用Scala解释器 15
2.2 第二步 变量定义 16
2.3 第三步 函数定义 18
2.4 第四步 编写Scala脚本 19
2.5 第五步 用while做循环;用if做判断 20
2.6 第六步 用foreach和for做枚举 21
2.7 小结 22
第3章 Scala入门再探 23
3.1 第七步 使用类型参数化数组(Array) 23
3.2 第八步 使用列表(List) 25
3.3 第九步 使用元组(Tuple) 28
3.4 第十步 使用集(set)和映射(map) 29
3.5 第十一步 学习识别函数式风格 32
3.6 第十二步 从文件里读取文本行 34
3.7 小结 36
第4章 类和对象 37
4.1 类、字段和方法 37
4.2 分号推断 40
4.3 Singleton对象 41
4.4 Scala程序 43
4.5 Application特质 45
4.6 小结 45
第5章 基本类型和操作 47
5.1 基本类型 47
5.2 字面量 48
5.3 操作符和方法 52
5.4 数学运算 54
5.5 关系和逻辑操作 55
5.6 位操作符 56
5.7 对象相等性 57
5.8 操作符的优先级和关联性 58
5.9 富包装器 60
5.10 小结 60
第6章 函数式对象 61
6.1 类Rational的规格说明书 61
6.2 创建Rational 62
6.3 重新实现toString方法 63
6.4 检查先决条件 63
6.5 添加字段 64
6.6 自指向 65
6.7 辅助构造器 65
6.8 私有字段和方法 66
6.9 定义操作符 67
6.10 Scala的标识符 68
6.11 方法重载 70
6.12 隐式转换 71
6.13 一番告诫 72
6.14 小结 72
第7章 内建控制结构 73
7.1 If表达式 73
7.2 While循环 74
7.3 for表达式 76
7.4 使用try表达式处理异常 80
7.5 匹配(match)表达式 82
7.6 不再使用break和continue 83
7.7 变量范围 84
7.8 重构指令式风格的代码 87
7.9 小结 88
第8章 函数和闭包 89
8.1 方法 89
8.2 本地函数 90
8.3 头等函数 91
8.4 函数字面量的短格式 93
8.5 占位符语法 93
8.6 部分应用函数 94
8.7 闭包 96
8.8 重复参数 98
8.9 尾递归 99
8.10 小结 102
第9章 控制抽象 103
9.1 减少代码重复 103
9.2 简化客户代码 106
9.3 柯里化(currying) 107
9.4 编写新的控制结构 108
9.5 传名参数(by-name parameter) 110
9.6 小结 112
第10章 组合与继承 113
10.1 二维布局库 113
10.2 抽象类 114
10.3 定义无参数方法 114
10.4 扩展类 116
10.5 重写方法和字段 117
10.6 定义参数化字段 118
10.7 调用超类构造器 119
10.8 使用override修饰符 120
10.9 多态和动态绑定 121
10.10 定义final成员 123
10.11 使用组合与继承 124
10.12 实现above、beside和toString 124
10.13 定义工厂对象 126
10.14 变高变宽 128
10.15 把代码都放在一起 129
10.16 小结 130
第11章 Scala的层级 131
11.1 Scala的类层级 131
11.2 原始类型是如何实现的 134
11.3 底层类型 135
11.4 小结 136
第12章 特质 137
12.1 特质是如何工作的 137
12.2 瘦接口对阵胖接口 139
12.3 样例:长方形对象 140
12.4 Ordered特质 141
12.5 特质用来做可堆叠的改变 143
12.6 为什么不是多重继承? 146
12.7 特质,用还是不用? 148
12.8 小结 149
第13章 包和引用 151
13.1 包 151
13.2 引用 153
13.3 隐式引用 156
13.4 访问修饰符 156
13.5 小结 160
第14章 断言和单元测试 161
14.1 断言 161
14.2 Scala里的单元测试 162
14.3 翔实的失败报告 163
14.4 使用JUnit和TestNG 164
14.5 规格测试 166
14.6 基于属性的测试 167
14.7 组织和运行测试 168
14.8 小结 170
第15章 样本类和模式匹配 171
15.1 简单例子 171
15.2 模式的种类 174
15.3 模式守卫 180
15.4 模式重叠 181
15.5 封闭类 182
15.6 Option类型 183
15.7 模式无处不在 184
15.8 一个更大的例子 187
15.9 小结 192
第16章 使用列表 193
16.1 列表字面量 193
16.2 List类型 193
16.3 构造列表 194
16.4 列表的基本操作 194
16.5 列表模式 195
16.6 List类的一阶方法 196
16.7 List类的高阶方法 204
16.8 List对象的方法 210
16.9 了解Scala的类型推断算法 212
16.10 小结 214
第17章 集合类型 215
17.1 集合库概览 215
17.2 序列 216
17.3 集(Set)和映射(Map) 220
17.4 可变(mutable)集合vs.不可变(immutable)集合 227
17.5 初始化集合 229
17.6 元组 231
17.7 小结 232
第18章 有状态的对象 233
18.1 什么让对象具有状态? 233
18.2 可重新赋值的变量和属性 234
18.3 案例研究:离散事件模拟 237
18.4 为数字电路定制的语言 237
18.5 Simulation API 239
18.6 电路模拟 242
18.7 小结 247
第19章 类型参数化 249
19.1 queues函数式队列 249
19.2 信息隐藏 251
19.3 变化型注解 253
19.4 检查变化型注解 256
19.5 下界 258
19.6 逆变 259
19.7 对象私有数据 261
19.8 上界 263
19.9 小结 264
第20章 抽象成员 265
20.1 抽象成员的快速浏览 265
20.2 类型成员 266
20.3 抽象val 266
20.4 抽象var 267
20.5 初始化抽象val 267
20.6 抽象类型 273
20.7 路径依赖类型 274
20.8 枚举 276
20.9 案例研究:货币 277
20.10 小结 284
第21章 隐式转换和参数 285
21.1 隐式转换 285
21.2 隐式操作规则 287
21.3 隐式转换为期望类型 289
21.4 转换(方法调用的)接收者 290
21.5 隐式参数 292
21.6 视界 296
21.7 隐式操作调试 297
21.8 小结 299
第22章 实现列表 301
22.1 List类原理 301
22.2 ListBuffer类 305
22.3 实际的List类 306
22.4 外在的函数式(风格) 308
22.5 小结 308
第23章 重访For表达式 309
23.1 For表达式 310
23.2 皇后问题 311
23.3 使用for表达式做查询 313
23.4 for表达式的转译 314
23.5 反其道而行之 317
23.6 泛化的for 318
23.7 小结 319
第24章 抽取器(Extractors) 321
24.1 例子:抽取email地址 321
24.2 抽取器 322
24.3 0或1个变量的模式 324
24.4 变参抽取器 325
24.5 抽取器和序列模式 327
24.6 抽取器VS.样本类 327
24.7 正则表达式 328
24.8 小结 330
第25章 注解 331
25.1 为什么要有注解? 331
25.2 注解语法 332
25.3 标准注解 333
25.4 小结 334
第26章 使用XML 335
26.1 半结构化数据 335
26.2 XML概览 335
26.3 XML字面量 336
26.4 序列化 338
26.5 拆解XML 339
26.6 反序列化 340
26.7 加载和保存 341
26.8 XML的模式匹配 342
26.9 小结 344
第27章 使用对象的模块化编程 345
27.1 问题 345
27.2 食谱应用 346
27.3 抽象概念 348
27.4 把模块拆分为特质 350
27.5 运行期链接 352
27.6 跟踪模块实例 353
27.7 小结 354
第28章 对象相等性 355
28.1 Scala中的相等性 355
28.2 编写相等性方法 355
28.3 定义带参数类型的相等性 365
28.4 equals和hashCode的制作方法 368
28.5 小结 371
第29章 结合Scala和Java 373
29.1 在Java中使用Scala 373
29.2 注解 375
29.3 存在类型 379
29.4 小结 381
第30章 Actor和并发 383
30.1 天堂中的烦恼 383
30.2 actor和消息传递 384
30.3 将原生线程当作actor 387
30.4 通过重用线程获得更好的性能 387
30.5 良好的actor风格 389
30.6 更长一些的示例:并行离散事件模拟 394
30.7 小结 406
第31章 连结符解析 407
31.1 示例:算术表达式 408
31.2 运行你的解析器 409
31.3 基本的正则表达式解析器 410
31.4 另一个示例:JSON 410
31.5 解析器输出 412
31.6 实现连结符解析器 416
31.7 字符串字面量和正则表达式 421
31.8 词法分析和解析 422
31.9 错误报告 423
31.10 回溯vs. LL(1) 424
31.11 小结 425
第32章 GUI编程 427
32.1 第一个Swing应用 427
32.2 面板和布局 429
32.3 处理事件 430
32.4 示例:摄氏/华氏温度转换器 432
32.5 小结 434
第33章 Scell试算表 435
33.1 可视化框架 435
33.2 将数据录入和显示分开 437
33.3 公式 439
33.4 解析公式 440
33.5 求值 444
33.6 操作库 446
33.7 修改传达 448
33.8 小结 451
附录A Unix和Windows的Scala脚本 453
术语表 455
参考文献 465
关于作者 467
索引 469
兼容 Java。这点很明显(其他 200 多种 JVM 上的语言也兼容 Java),但它是如此重要的一个功能,因此不可小视。它意味着 Scala 可以使用所有 Java 库和框架爱。这也是对那些投资该技术的人员和公司的表达敬意。
联合编译(Joint Compilation)。这表示与 Groovy 类似,Scala 类被编译为 Java 类,因此可以在 Java 项目中使用(甚至在他们被定义的同一项目中的 java 类 使用)。即使你的团队觉得完全转向 Scala,对于通过 JSR 223 整合动态语言,这依然很有用。
类型推断(Type Inference)。如果编译器能猜到类型(通常它可以做到),你就不必告诉它。这使得 Scala 代码具有动态语言的简洁性,而同时保持类型安全。
隐式转换(Implicit conversion),使 Scala 具有类型安全性,正如扩展方法(extension method)之于 C#,开放类(open class)之于 ruby。即:向你未曾定义的类型添加方法(如字符串、列表、整数)。这是使得 Scala 符合 DSL(特定领域语言)模型的特性之一。
鼓励使用对象不变性,并且容易实现。Scala 甚至提供了内置的不变对象垃圾收集器。对于Scala有这样一种说法:“每当提到不变性时,有人就会开始担心性能的问题,对于某些情况,这种担忧并非毫无来由,但对于 Scala,最终结果却与这一担忧相反。不可变的数据结构相对于可变的数据结构,更有助于获得较高的效率。其原因之一在于强大的垃圾收集器(garbage collector),与 JVM 中的垃圾收集器类似。”
自动生成 Getter 和 Setter,如果你不需要(比如你只需 Setter),你必须显示地将他们私有化(private)。这不是问题,因为通常情况都需要。
Scala 具有第一等级(first-order)函数并通过 iterable trait 实现了枚举协议(enumeration protocol),这有助于让代码更加干净、更加简洁,并能够带来其他一些好处。
Actor 编程模式让高度并行应用程序的开发更加简单。
不必显示抓取或抛出(try-catch)异常。可以认为使用已检查异常(checked exception)的害处多于好处。
有关Scala更多的好处,可以参考51CTO之前发布的Ruby高手点评Scala编程语言十大绝招一文。不过,单单这些特性就已足够——足够令 Scala 成为一个非常有趣的语言,足够让 JRuby 创建者之一 Charles Nutter 宣称它就是 Java 王位的合法继承人,甚至足够让 Groovy 的创建人 James Stracha 以及 Java 的创建人 James Gosling 为其背书。尽管如此,Scala 是一个具有深度的语言,还有几项高级特性,可以让开发者更具生产力。但在掌握基本知识之前就学习这些功能会让人感觉非常困难,如果没有很好的支持文档(比如 IBM、 Aritma、Jonas Bonér、Daniel Spiewak、Sven Efftinge 以及官方和其他网站提供的资料)会更加困难。不过,这不仅仅是令人兴奋,在你需要时,它确实可以用来进一步挖掘更具深度的一些概念。
51CTO编辑推荐:Scala编程语言专题
即使 Scala 具有学术性的根源(正如在它的论文网页上显示的那样,以及它涉及的某些高深概念),它已成功应用在企业项目上,除 Twitter 之外,还有西门子、法国电力集团(électricité de France)和 WattzOn 网站。
在所有这些优点之外,Scala 的确还存在一些粗糙的地方。虽然很多正在努力解决这些弱点,但近期内它们还是有影响的:
◆刚刚起步的 IDE 支持。正如 Lift 的作者所言,Scala 的 IDE 支持,虽然进行了很多开发,还没有做到 Java 那种地步。重构支持、代码完整以及单元测试整合都很差。更不必说大多数框架支持工具不能很好地与 Scala 兼容。由于 IDE 能够帮助人们学习这种语言,这可能吓退那些新手。另一方面,Martin Folwer 认为这种 IDE 状况是相对的,一种让你更具生产力的语言足以弥补缺乏高级工具的弱点。
◆大多数 IDE 不支持联合编译。同样,当 Scala 更加普及之后,这一点会有所改变。
◆类的不变性并非真的不变性,因为引用对象自身可能不是不变的。并且目前没有方法可以确保整个对象图谱是不变的。
◆让 JSR 223 完美地兼容 Scala 非常困难。但另一方面,取得足够好的兼容还是相当容易的。
◆Scala 不支持元编程(metaprogramming)。通过将其与动态语言结合,如 Ruby,可以绕过这个问题,但如果你是元编程的重度使用者,使用一个完全不同的语言是一种较好的解决办法(Fan 是另一个运行在 JVM 上的静态类型语言,与 Scala 类似,但支持元编程)。
◆使用 Java 资源的框架,如客户端 GWT,不能很好地兼容 Scala(虽然有人已经在服务器端让 Scala 与 GWT 兼容)。不过,有一个项目正在进行,将能够使 Scala 转化为 Java 资源。
◆语法和某些概念与 Java 有点不同,比如:颠倒的类型声明顺序、使用下划线而不是通配符、星号和缺省值,太多种类的空概念(nothing)、没有静态方法(你需要使用单例对象 singleton object 作为替代)。文档对这些问题有很好的解释,但是,请留意,这不是 Java 代码到 Scala 代码的自动转换。
正如 Joe Amstrong 所说,随着 CPU 变得更加廉价,具有越来越多的内核,开发者能够更加简便地使用多核 CPU 的语言需求,将会不断增加。Scala 恰好满足了这种需求,而同时 Java 的开发停滞不前,纠缠于广泛部署所带来的问题,以及未来有多开放的不确定性和某些主要贡献者的政治问题。根据这种情况来看,Scala 非常适合 Java 王位继承者这一角色。
1. 语法错误
认为 “yield” 像 ”return” 一样。有人会这样写:
for(i <- 0 to 10) {
if (i % 2 == 0)
yield i
else
yield -i
}
正确的表示应该是:
for(i <- 0 to 10)
yield {
if (i % 2 == 0)
i
else
-i
}
2. 误用和语法错误
滥用scala.xml.XML.loadXXX。这个的语法分析器试图访问外部的DTD、strip组件或类似的东西。在scala.xml.parsing.ConstructingParser.fromXXX中有另一个可选的语法分析器。同时,在处理XML时忘记了等号两端的空格。比如:
val xml=
这段代码真正的意思是:
val xml.$equal$less(root).$slash$greater
这种情况的发生是由于操作符相当随意,而且scala采用这样一种事实:字母数字字符与非字母数字字符通过下划线可以结合成为一个有效的标识符。这也使得“x+y”这样的表达式不会被当成一个标识符。而应该注意 “x_+”是一个有效的标识符。所以,赋值标识符的写法应该是:
val xml =
3. 用法错误
为那些根本不是无关紧要的应用加入Application特征。
object MyScalaApp extends Application {
// ... body ...
}
示例部分的问题在于,body部分在单元对象初始化时执行。首先,单元初始化的执行是异步的,因此你的整个程序不能与其它线程交互;其次,即时编译器(JIT)不会优化它,因此你的程序速度慢下来,这是没有必要的。
另外,不能与其它线程的交互也意味着你会忘记测试应用程序的GUI或者Actors。
4. 用法错误
试图模式匹配一个字符串的正则表达式,而又假定该正则表达式是无界的:
val r = """(d+)""".r
val s = "--> 5 <--- br="" s="" match="" br="" case="" r="" n="" println="" this="" won="" t="" match="" br="" case="" _=">" println="" this="" will="" br="" br="" scala="" br="" val="" r="" d="" r="" br="" val="" s="--> 5 <---" br="" r="" findfirstin="" s="" match="" br="" case="" some="" n="" println="" matches="" 5="" to="" n="" br="" case="" _=">" println="" won="" t="" match="" br="" br="" br="" val="" r="" d="" r="" br="" val="" s="'--"> 5 <---"
s match {
case r(n) => println("This will match the first group of r, "+n+", to 5")
case _ => println("Won't match")
}
5. 用法错误
把var和val认为是字段(fields):
Scala强制使用统一访问准则(Uniform Access Principle),这使得我们无法直接引用一个字段。所有对任意字段的访问只能通过getters和setters。val和var事实上只是定义一个字段,getter作为val字段,对于var则定义一个setter。
Java程序员通常认为var和val是字段,而当发现在他们的方法中它们共享相同的命名空间时,常常觉得惊讶。因此,不能重复使用它们的名字。共享命名空间的是自动定义的getter和setter而不是字段本身。通常程序员们会试图寻找一种访问字段的方法,从而可以绕过限制——但这只是徒劳,统一访问准则是无法违背的。它的另一个后果是,当进行子类化时val会覆盖def。其它方法是行不通的,因为val增加了不变性保证,而def没有。
当你需要重载时,没有任何准则会指导你如何使用私有的getters和setters。Scala编译器和库代码常使用私有值的别名和缩写,反之公有的getters和setters则使用fullyCamelNamingConventions(一种命名规范)。其它的建议包括:重命名、实例中的单元化,甚至子类化。这些建议的例子如下:
重命名
class User(val name: String, initialPassword: String) {
private lazy var encryptedPassword = encrypt(initialPassword, salt)
private lazy var salt = scala.util.Random.nextInt
private def encrypt(plainText: String, salt: Int): String = { ... }
private def decrypt(encryptedText: String, salt: Int): String = { ... }
def password = decrypt(encryptedPassword, salt)
def password_=(newPassword: String) = encrypt(newPassword, salt)
}
单例模式(Singleton)
class User(initialName: String, initialPassword: String) {
private object fields {
var name: String = initialName;
var password: String = initialPassword;
}
def name = fields.name
def name_=(newName: String) = fields.name = newName
def password = fields.password
def password_=(newPassword: String) = fields.password = newPassword
}
或者,对于一个类来说,可以为相等关系或hashCode自动定义可被重用的方法
class User(name0: String, password0: String) {
private case class Fields(var name: String, var password0: String)
private object fields extends Fields(name0, password0)
def name = fields.name
def name_=(newName: String) = fields.name = newName
def password = fields.password
def password_=(newPassword: String) = fields.password = newPassword
}
子类化
case class Customer(name: String)
class ValidatingCustomer(name0: String) extends Customer(name0) {
require(name0.length < 5)
def name_=(newName : String) =
if (newName.length < 5) error("too short")
else super.name_=(newName)
}
val cust = new ValidatingCustomer("xyz123")
6. 用法错误
忘记类型擦除(type erasure)。当你声明了一个类C[A]、一个泛型T[A]或者一个函数或者方法m[A]后,A在运行时并不存在。这意味着,对于实例来讲,任何参数都将被编译成AnyRef,即使编译器能够保证在编译过程中类型不会被忽略掉。
这也意味着在编译时你不能使用类型参数A。例如,下面这些代码将不会工作:
def checkList[A](l: List[A]) = l match {
case _ : List[Int] => println("List of Ints")
case _ : List[String] => println("List of Strings")
case _ => println("Something else")
}
在运行时,被传递的List没有类型参数。 而List[Int]和List[String]都将会变成List[_]. 因此只有第一种情况会被调用。
你也可以在一定范围内不使用这种方法,而采用实验性的特性Manifest, 像这样:
def checkList[A](l: List[A])(implicit m: scala.reflect.Manifest[A]) = m.toString match {
case "int" => println("List of Ints")
case "java.lang.String" => println("List of Strings")
case _ => println("Something else")
}
7. 设计错误
Implicit关键字的使用不小心。Implicits非常强大,但要小心,普通类型不能使用隐式参数或者进行隐匿转换。
例如,下面一个implicit表达式:
implicit def string2Int(s: String): Int = s.toInt
这是一个不好的做法,因为有人可能错误的使用了一个字符串来代替Int。对于上面的这种情况,更好的方法是使用一个类。
case class Age(n: Int)
implicit def string2Age(s: String) = Age(s.toInt)
implicit def int2Age(n: Int) = new Age(n)
implicit def age2Int(a: Age) = a.n
这将会使你很自由的将Age与String或者Int结合起来,而不是让String和Int结合。类似的,当使用隐式参数时,不要像这样做:
case class Person(name: String)(implicit age: Int)
这不仅因为它容易在隐式参数间产生冲突,而且可能导致在毫无提示情况下传递一个隐式的age, 而接收者需要的只是隐式的Int或者其它类型。同样,解决办法是使用一个特定的类。
另一种可能导致implicit用法出问题的情况是有偏好的使用操作符。你可能认为”~”是字符串匹配时最好的操作符,而其他人可能会使用矩阵等价(matrix equivalence),分析器连接等(符号)。因此,如果你使用它们,请确保你能够很容易的分离其作用域。
8. 设计错误
设计不佳的等价方法。尤其是:
◆试着使用“==”代替“equals”(这让你可以使用“!=”)
◆使用这样的定义:
def equals(other: MyClass): Boolean
而不是这样的:
override def equals(other: Any): Boolean
◆忘记重载hashCode,以确保当a==b时a.hashCode==b.hashCode(反之不一定成立)。
◆不可以这样做交换: if a==b then b==a。特别地,当考虑子类化时,超类是否知道如何与一个子类进行对比,即使它不知道该子类是否存在。如果需要请查看canEquals的用法。
◆不可以这样做传递: if a==b and b ==c then a==c。
9. 用法错误
在Unix/Linux/*BSD的系统中,对你的主机进行了命名却没有在主机文件中声明。特别的,下面这条指令不会工作:
ping `hostname`
在这种情况下,fsc和scala都不会工作,而scalac则可以。这是因为fsc运行在背景模式下,通过TCP套接字监听连接来加速编译,而scala却用它来加快脚本的执行速度。
10.风格错误
使用while。虽然它有自己的用处,但大多数时候使用for往往更好。在谈到for时,用它们来产生索引不是一个好的做法。
避免这样的使用:
def matchingChars(string: String, characters: String) = {
var m = ""
for(i <- 0 until string.length)
if ((characters contains string(i)) && !(m contains string(i)))
m += string(i)
m
}
而应该使用:
def matchingChars(string: String, characters: String) = {
var m = ""
for(c <- string)
if ((characters contains c) && !(m contains c))
m += c
m
}
如果有人需要返回一个索引,可以使用下面的形式来代替按索引迭代的方法。如果对性能有要求,它可以较好的应用在投影(projection)(Scala 2.7)和视图(Scala 2.8)中。
def indicesOf(s: String, c: Char) = for {
(sc, index) <- s.zipWithIndex
if c == sc
} yield index
禁用于商业用途!如果您喜欢《Scala编程》,请购买正版,谢谢合作。
爱学习,请到3322软件站查找资源自行下载!
1、下载并解压,得出pdf文件
2、如果打不开本文件,别着急,这时候请务必在3322软件站选择一款阅读器下载哦
3、安装后,再打开解压得出的pdf文件
4、以上都完成后,接下来双击进行阅读就可以啦,朋友们开启你们的阅读之旅吧。
方法二:
1、可以在手机里下载3322软件站中的阅读器和百度网盘
2、接下来直接将pdf传输到百度网盘
3、用阅读器打开即可阅读
Scala语言简介
Scala是一种针对 JVM 将函数和面向对象技术组合在一起的编程语言。Scala编程语言近来抓住了很多开发者的眼球。它看起来像是一种纯粹的面向对象编程语言,而又无缝地结合了命令式和函数式的编程风格。Scala的名称表明,它还是一种高度可伸缩的语言。Scala的设计始终贯穿着一个理念:创造一种更好地支持组件的语言。Scala融汇了许多前所未有的特性,而同时又运行于JVM之上。随着开发者对Scala的兴趣日增,以及越来越多的工具支持,无疑Scala语言将成为你手上一件必不可少的工具。关于作者
Martin Odersky是Scala语言的创造者。作为瑞士洛桑联邦理工学院(EPFL)的教授,他主要从事编程语言领域的工作。更具体地说,是面向对象和函数式编程的语言。他研究的论题是,这两种编程模式是硬币的两面,应该被尽可能地统一在一起。为了证明这点,他已试验性地设计了大量的语言,从Pizza到GJ到Functional Nets语言 。他还作为Java泛型的联合设计师及当前javac参考编译器的原作者影响了Java的发展。从2001年起,他主要从事Scala编程语言的设计、实现及改进工作。Lex Spoon是Google的软件工程师。他以EPFL博士后身份在Scala方面工作了两年时间,从佐治亚理工学院(Georgia Tech)获得计算机科学的博士学位。那时他的主要工作是动态语言的静态分析。除了Scala之外,他还从事大量其他的编程语言工作,范围从动态语言Smalltalk到科学性语言X10。他和他的妻子,两只猫、一条吉娃娃还有一只乌龟,现生活于亚特兰大。
Bill Venners是Artima的总裁,兼Artima开发者网站(www.artima.com)的发行人。他是《深入Java虚拟机》(“Inside the Java Virtual Machine”)的作者,该书是定向为程序员的Java平台架构和内部组织的总体研究。他在JavaWorld杂志上有很受欢迎的专栏,内容涵盖Java内部机制,面向对象设计,还有Jini。Bill从Jini诞生伊始就活跃于Jini社区,他曾领导Jini社区的ServiceUI项目,而其中的ServiceUI API已经变成了联系用户界面和Jini服务之间的事实标准。Bill还是ScalaTest(Scala和Java开发的开源测试工具)的首席开发者(lead developer)和设计者。
Scala编程目录
目录 ix图示清单 xvii
表格清单 xix
代码清单 xxi
序 I
致谢 III
简介 V
第1章 可伸展的语言 3
1.1 与你一同成长的语言 3
1.2 是什么让Scala具有可扩展性? 6
1.3 为什么选择Scala? 8
1.4 Scala的根源 13
1.5 小结 14
第2章 Scala入门初探 15
2.1 第一步 学习使用Scala解释器 15
2.2 第二步 变量定义 16
2.3 第三步 函数定义 18
2.4 第四步 编写Scala脚本 19
2.5 第五步 用while做循环;用if做判断 20
2.6 第六步 用foreach和for做枚举 21
2.7 小结 22
第3章 Scala入门再探 23
3.1 第七步 使用类型参数化数组(Array) 23
3.2 第八步 使用列表(List) 25
3.3 第九步 使用元组(Tuple) 28
3.4 第十步 使用集(set)和映射(map) 29
3.5 第十一步 学习识别函数式风格 32
3.6 第十二步 从文件里读取文本行 34
3.7 小结 36
第4章 类和对象 37
4.1 类、字段和方法 37
4.2 分号推断 40
4.3 Singleton对象 41
4.4 Scala程序 43
4.5 Application特质 45
4.6 小结 45
第5章 基本类型和操作 47
5.1 基本类型 47
5.2 字面量 48
5.3 操作符和方法 52
5.4 数学运算 54
5.5 关系和逻辑操作 55
5.6 位操作符 56
5.7 对象相等性 57
5.8 操作符的优先级和关联性 58
5.9 富包装器 60
5.10 小结 60
第6章 函数式对象 61
6.1 类Rational的规格说明书 61
6.2 创建Rational 62
6.3 重新实现toString方法 63
6.4 检查先决条件 63
6.5 添加字段 64
6.6 自指向 65
6.7 辅助构造器 65
6.8 私有字段和方法 66
6.9 定义操作符 67
6.10 Scala的标识符 68
6.11 方法重载 70
6.12 隐式转换 71
6.13 一番告诫 72
6.14 小结 72
第7章 内建控制结构 73
7.1 If表达式 73
7.2 While循环 74
7.3 for表达式 76
7.4 使用try表达式处理异常 80
7.5 匹配(match)表达式 82
7.6 不再使用break和continue 83
7.7 变量范围 84
7.8 重构指令式风格的代码 87
7.9 小结 88
第8章 函数和闭包 89
8.1 方法 89
8.2 本地函数 90
8.3 头等函数 91
8.4 函数字面量的短格式 93
8.5 占位符语法 93
8.6 部分应用函数 94
8.7 闭包 96
8.8 重复参数 98
8.9 尾递归 99
8.10 小结 102
第9章 控制抽象 103
9.1 减少代码重复 103
9.2 简化客户代码 106
9.3 柯里化(currying) 107
9.4 编写新的控制结构 108
9.5 传名参数(by-name parameter) 110
9.6 小结 112
第10章 组合与继承 113
10.1 二维布局库 113
10.2 抽象类 114
10.3 定义无参数方法 114
10.4 扩展类 116
10.5 重写方法和字段 117
10.6 定义参数化字段 118
10.7 调用超类构造器 119
10.8 使用override修饰符 120
10.9 多态和动态绑定 121
10.10 定义final成员 123
10.11 使用组合与继承 124
10.12 实现above、beside和toString 124
10.13 定义工厂对象 126
10.14 变高变宽 128
10.15 把代码都放在一起 129
10.16 小结 130
第11章 Scala的层级 131
11.1 Scala的类层级 131
11.2 原始类型是如何实现的 134
11.3 底层类型 135
11.4 小结 136
第12章 特质 137
12.1 特质是如何工作的 137
12.2 瘦接口对阵胖接口 139
12.3 样例:长方形对象 140
12.4 Ordered特质 141
12.5 特质用来做可堆叠的改变 143
12.6 为什么不是多重继承? 146
12.7 特质,用还是不用? 148
12.8 小结 149
第13章 包和引用 151
13.1 包 151
13.2 引用 153
13.3 隐式引用 156
13.4 访问修饰符 156
13.5 小结 160
第14章 断言和单元测试 161
14.1 断言 161
14.2 Scala里的单元测试 162
14.3 翔实的失败报告 163
14.4 使用JUnit和TestNG 164
14.5 规格测试 166
14.6 基于属性的测试 167
14.7 组织和运行测试 168
14.8 小结 170
第15章 样本类和模式匹配 171
15.1 简单例子 171
15.2 模式的种类 174
15.3 模式守卫 180
15.4 模式重叠 181
15.5 封闭类 182
15.6 Option类型 183
15.7 模式无处不在 184
15.8 一个更大的例子 187
15.9 小结 192
第16章 使用列表 193
16.1 列表字面量 193
16.2 List类型 193
16.3 构造列表 194
16.4 列表的基本操作 194
16.5 列表模式 195
16.6 List类的一阶方法 196
16.7 List类的高阶方法 204
16.8 List对象的方法 210
16.9 了解Scala的类型推断算法 212
16.10 小结 214
第17章 集合类型 215
17.1 集合库概览 215
17.2 序列 216
17.3 集(Set)和映射(Map) 220
17.4 可变(mutable)集合vs.不可变(immutable)集合 227
17.5 初始化集合 229
17.6 元组 231
17.7 小结 232
第18章 有状态的对象 233
18.1 什么让对象具有状态? 233
18.2 可重新赋值的变量和属性 234
18.3 案例研究:离散事件模拟 237
18.4 为数字电路定制的语言 237
18.5 Simulation API 239
18.6 电路模拟 242
18.7 小结 247
第19章 类型参数化 249
19.1 queues函数式队列 249
19.2 信息隐藏 251
19.3 变化型注解 253
19.4 检查变化型注解 256
19.5 下界 258
19.6 逆变 259
19.7 对象私有数据 261
19.8 上界 263
19.9 小结 264
第20章 抽象成员 265
20.1 抽象成员的快速浏览 265
20.2 类型成员 266
20.3 抽象val 266
20.4 抽象var 267
20.5 初始化抽象val 267
20.6 抽象类型 273
20.7 路径依赖类型 274
20.8 枚举 276
20.9 案例研究:货币 277
20.10 小结 284
第21章 隐式转换和参数 285
21.1 隐式转换 285
21.2 隐式操作规则 287
21.3 隐式转换为期望类型 289
21.4 转换(方法调用的)接收者 290
21.5 隐式参数 292
21.6 视界 296
21.7 隐式操作调试 297
21.8 小结 299
第22章 实现列表 301
22.1 List类原理 301
22.2 ListBuffer类 305
22.3 实际的List类 306
22.4 外在的函数式(风格) 308
22.5 小结 308
第23章 重访For表达式 309
23.1 For表达式 310
23.2 皇后问题 311
23.3 使用for表达式做查询 313
23.4 for表达式的转译 314
23.5 反其道而行之 317
23.6 泛化的for 318
23.7 小结 319
第24章 抽取器(Extractors) 321
24.1 例子:抽取email地址 321
24.2 抽取器 322
24.3 0或1个变量的模式 324
24.4 变参抽取器 325
24.5 抽取器和序列模式 327
24.6 抽取器VS.样本类 327
24.7 正则表达式 328
24.8 小结 330
第25章 注解 331
25.1 为什么要有注解? 331
25.2 注解语法 332
25.3 标准注解 333
25.4 小结 334
第26章 使用XML 335
26.1 半结构化数据 335
26.2 XML概览 335
26.3 XML字面量 336
26.4 序列化 338
26.5 拆解XML 339
26.6 反序列化 340
26.7 加载和保存 341
26.8 XML的模式匹配 342
26.9 小结 344
第27章 使用对象的模块化编程 345
27.1 问题 345
27.2 食谱应用 346
27.3 抽象概念 348
27.4 把模块拆分为特质 350
27.5 运行期链接 352
27.6 跟踪模块实例 353
27.7 小结 354
第28章 对象相等性 355
28.1 Scala中的相等性 355
28.2 编写相等性方法 355
28.3 定义带参数类型的相等性 365
28.4 equals和hashCode的制作方法 368
28.5 小结 371
第29章 结合Scala和Java 373
29.1 在Java中使用Scala 373
29.2 注解 375
29.3 存在类型 379
29.4 小结 381
第30章 Actor和并发 383
30.1 天堂中的烦恼 383
30.2 actor和消息传递 384
30.3 将原生线程当作actor 387
30.4 通过重用线程获得更好的性能 387
30.5 良好的actor风格 389
30.6 更长一些的示例:并行离散事件模拟 394
30.7 小结 406
第31章 连结符解析 407
31.1 示例:算术表达式 408
31.2 运行你的解析器 409
31.3 基本的正则表达式解析器 410
31.4 另一个示例:JSON 410
31.5 解析器输出 412
31.6 实现连结符解析器 416
31.7 字符串字面量和正则表达式 421
31.8 词法分析和解析 422
31.9 错误报告 423
31.10 回溯vs. LL(1) 424
31.11 小结 425
第32章 GUI编程 427
32.1 第一个Swing应用 427
32.2 面板和布局 429
32.3 处理事件 430
32.4 示例:摄氏/华氏温度转换器 432
32.5 小结 434
第33章 Scell试算表 435
33.1 可视化框架 435
33.2 将数据录入和显示分开 437
33.3 公式 439
33.4 解析公式 440
33.5 求值 444
33.6 操作库 446
33.7 修改传达 448
33.8 小结 451
附录A Unix和Windows的Scala脚本 453
术语表 455
参考文献 465
关于作者 467
索引 469
优缺点介绍
Scala 的各种特性能够为你带来最直接的好处:兼容 Java。这点很明显(其他 200 多种 JVM 上的语言也兼容 Java),但它是如此重要的一个功能,因此不可小视。它意味着 Scala 可以使用所有 Java 库和框架爱。这也是对那些投资该技术的人员和公司的表达敬意。
联合编译(Joint Compilation)。这表示与 Groovy 类似,Scala 类被编译为 Java 类,因此可以在 Java 项目中使用(甚至在他们被定义的同一项目中的 java 类 使用)。即使你的团队觉得完全转向 Scala,对于通过 JSR 223 整合动态语言,这依然很有用。
类型推断(Type Inference)。如果编译器能猜到类型(通常它可以做到),你就不必告诉它。这使得 Scala 代码具有动态语言的简洁性,而同时保持类型安全。
隐式转换(Implicit conversion),使 Scala 具有类型安全性,正如扩展方法(extension method)之于 C#,开放类(open class)之于 ruby。即:向你未曾定义的类型添加方法(如字符串、列表、整数)。这是使得 Scala 符合 DSL(特定领域语言)模型的特性之一。
鼓励使用对象不变性,并且容易实现。Scala 甚至提供了内置的不变对象垃圾收集器。对于Scala有这样一种说法:“每当提到不变性时,有人就会开始担心性能的问题,对于某些情况,这种担忧并非毫无来由,但对于 Scala,最终结果却与这一担忧相反。不可变的数据结构相对于可变的数据结构,更有助于获得较高的效率。其原因之一在于强大的垃圾收集器(garbage collector),与 JVM 中的垃圾收集器类似。”
自动生成 Getter 和 Setter,如果你不需要(比如你只需 Setter),你必须显示地将他们私有化(private)。这不是问题,因为通常情况都需要。
Scala 具有第一等级(first-order)函数并通过 iterable trait 实现了枚举协议(enumeration protocol),这有助于让代码更加干净、更加简洁,并能够带来其他一些好处。
Actor 编程模式让高度并行应用程序的开发更加简单。
不必显示抓取或抛出(try-catch)异常。可以认为使用已检查异常(checked exception)的害处多于好处。
有关Scala更多的好处,可以参考51CTO之前发布的Ruby高手点评Scala编程语言十大绝招一文。不过,单单这些特性就已足够——足够令 Scala 成为一个非常有趣的语言,足够让 JRuby 创建者之一 Charles Nutter 宣称它就是 Java 王位的合法继承人,甚至足够让 Groovy 的创建人 James Stracha 以及 Java 的创建人 James Gosling 为其背书。尽管如此,Scala 是一个具有深度的语言,还有几项高级特性,可以让开发者更具生产力。但在掌握基本知识之前就学习这些功能会让人感觉非常困难,如果没有很好的支持文档(比如 IBM、 Aritma、Jonas Bonér、Daniel Spiewak、Sven Efftinge 以及官方和其他网站提供的资料)会更加困难。不过,这不仅仅是令人兴奋,在你需要时,它确实可以用来进一步挖掘更具深度的一些概念。
51CTO编辑推荐:Scala编程语言专题
即使 Scala 具有学术性的根源(正如在它的论文网页上显示的那样,以及它涉及的某些高深概念),它已成功应用在企业项目上,除 Twitter 之外,还有西门子、法国电力集团(électricité de France)和 WattzOn 网站。
在所有这些优点之外,Scala 的确还存在一些粗糙的地方。虽然很多正在努力解决这些弱点,但近期内它们还是有影响的:
◆刚刚起步的 IDE 支持。正如 Lift 的作者所言,Scala 的 IDE 支持,虽然进行了很多开发,还没有做到 Java 那种地步。重构支持、代码完整以及单元测试整合都很差。更不必说大多数框架支持工具不能很好地与 Scala 兼容。由于 IDE 能够帮助人们学习这种语言,这可能吓退那些新手。另一方面,Martin Folwer 认为这种 IDE 状况是相对的,一种让你更具生产力的语言足以弥补缺乏高级工具的弱点。
◆大多数 IDE 不支持联合编译。同样,当 Scala 更加普及之后,这一点会有所改变。
◆类的不变性并非真的不变性,因为引用对象自身可能不是不变的。并且目前没有方法可以确保整个对象图谱是不变的。
◆让 JSR 223 完美地兼容 Scala 非常困难。但另一方面,取得足够好的兼容还是相当容易的。
◆Scala 不支持元编程(metaprogramming)。通过将其与动态语言结合,如 Ruby,可以绕过这个问题,但如果你是元编程的重度使用者,使用一个完全不同的语言是一种较好的解决办法(Fan 是另一个运行在 JVM 上的静态类型语言,与 Scala 类似,但支持元编程)。
◆使用 Java 资源的框架,如客户端 GWT,不能很好地兼容 Scala(虽然有人已经在服务器端让 Scala 与 GWT 兼容)。不过,有一个项目正在进行,将能够使 Scala 转化为 Java 资源。
◆语法和某些概念与 Java 有点不同,比如:颠倒的类型声明顺序、使用下划线而不是通配符、星号和缺省值,太多种类的空概念(nothing)、没有静态方法(你需要使用单例对象 singleton object 作为替代)。文档对这些问题有很好的解释,但是,请留意,这不是 Java 代码到 Scala 代码的自动转换。
正如 Joe Amstrong 所说,随着 CPU 变得更加廉价,具有越来越多的内核,开发者能够更加简便地使用多核 CPU 的语言需求,将会不断增加。Scala 恰好满足了这种需求,而同时 Java 的开发停滞不前,纠缠于广泛部署所带来的问题,以及未来有多开放的不确定性和某些主要贡献者的政治问题。根据这种情况来看,Scala 非常适合 Java 王位继承者这一角色。
常见错误
对于Scala编程, 我们收集了这些常见代码编写中的陷阱。这些技巧来自于Daniel Sobral,一个曾参加过FreeBSD项目和Java软件开发工程的Scala狂热爱好者。1. 语法错误
认为 “yield” 像 ”return” 一样。有人会这样写:
for(i <- 0 to 10) {
if (i % 2 == 0)
yield i
else
yield -i
}
正确的表示应该是:
for(i <- 0 to 10)
yield {
if (i % 2 == 0)
i
else
-i
}
2. 误用和语法错误
滥用scala.xml.XML.loadXXX。这个的语法分析器试图访问外部的DTD、strip组件或类似的东西。在scala.xml.parsing.ConstructingParser.fromXXX中有另一个可选的语法分析器。同时,在处理XML时忘记了等号两端的空格。比如:
val xml=
这段代码真正的意思是:
val xml.$equal$less(root).$slash$greater
这种情况的发生是由于操作符相当随意,而且scala采用这样一种事实:字母数字字符与非字母数字字符通过下划线可以结合成为一个有效的标识符。这也使得“x+y”这样的表达式不会被当成一个标识符。而应该注意 “x_+”是一个有效的标识符。所以,赋值标识符的写法应该是:
val xml =
3. 用法错误
为那些根本不是无关紧要的应用加入Application特征。
object MyScalaApp extends Application {
// ... body ...
}
示例部分的问题在于,body部分在单元对象初始化时执行。首先,单元初始化的执行是异步的,因此你的整个程序不能与其它线程交互;其次,即时编译器(JIT)不会优化它,因此你的程序速度慢下来,这是没有必要的。
另外,不能与其它线程的交互也意味着你会忘记测试应用程序的GUI或者Actors。
4. 用法错误
试图模式匹配一个字符串的正则表达式,而又假定该正则表达式是无界的:
val r = """(d+)""".r
val s = "--> 5 <--- br="" s="" match="" br="" case="" r="" n="" println="" this="" won="" t="" match="" br="" case="" _=">" println="" this="" will="" br="" br="" scala="" br="" val="" r="" d="" r="" br="" val="" s="--> 5 <---" br="" r="" findfirstin="" s="" match="" br="" case="" some="" n="" println="" matches="" 5="" to="" n="" br="" case="" _=">" println="" won="" t="" match="" br="" br="" br="" val="" r="" d="" r="" br="" val="" s="'--"> 5 <---"
s match {
case r(n) => println("This will match the first group of r, "+n+", to 5")
case _ => println("Won't match")
}
5. 用法错误
把var和val认为是字段(fields):
Scala强制使用统一访问准则(Uniform Access Principle),这使得我们无法直接引用一个字段。所有对任意字段的访问只能通过getters和setters。val和var事实上只是定义一个字段,getter作为val字段,对于var则定义一个setter。
Java程序员通常认为var和val是字段,而当发现在他们的方法中它们共享相同的命名空间时,常常觉得惊讶。因此,不能重复使用它们的名字。共享命名空间的是自动定义的getter和setter而不是字段本身。通常程序员们会试图寻找一种访问字段的方法,从而可以绕过限制——但这只是徒劳,统一访问准则是无法违背的。它的另一个后果是,当进行子类化时val会覆盖def。其它方法是行不通的,因为val增加了不变性保证,而def没有。
当你需要重载时,没有任何准则会指导你如何使用私有的getters和setters。Scala编译器和库代码常使用私有值的别名和缩写,反之公有的getters和setters则使用fullyCamelNamingConventions(一种命名规范)。其它的建议包括:重命名、实例中的单元化,甚至子类化。这些建议的例子如下:
重命名
class User(val name: String, initialPassword: String) {
private lazy var encryptedPassword = encrypt(initialPassword, salt)
private lazy var salt = scala.util.Random.nextInt
private def encrypt(plainText: String, salt: Int): String = { ... }
private def decrypt(encryptedText: String, salt: Int): String = { ... }
def password = decrypt(encryptedPassword, salt)
def password_=(newPassword: String) = encrypt(newPassword, salt)
}
单例模式(Singleton)
class User(initialName: String, initialPassword: String) {
private object fields {
var name: String = initialName;
var password: String = initialPassword;
}
def name = fields.name
def name_=(newName: String) = fields.name = newName
def password = fields.password
def password_=(newPassword: String) = fields.password = newPassword
}
或者,对于一个类来说,可以为相等关系或hashCode自动定义可被重用的方法
class User(name0: String, password0: String) {
private case class Fields(var name: String, var password0: String)
private object fields extends Fields(name0, password0)
def name = fields.name
def name_=(newName: String) = fields.name = newName
def password = fields.password
def password_=(newPassword: String) = fields.password = newPassword
}
子类化
case class Customer(name: String)
class ValidatingCustomer(name0: String) extends Customer(name0) {
require(name0.length < 5)
def name_=(newName : String) =
if (newName.length < 5) error("too short")
else super.name_=(newName)
}
val cust = new ValidatingCustomer("xyz123")
6. 用法错误
忘记类型擦除(type erasure)。当你声明了一个类C[A]、一个泛型T[A]或者一个函数或者方法m[A]后,A在运行时并不存在。这意味着,对于实例来讲,任何参数都将被编译成AnyRef,即使编译器能够保证在编译过程中类型不会被忽略掉。
这也意味着在编译时你不能使用类型参数A。例如,下面这些代码将不会工作:
def checkList[A](l: List[A]) = l match {
case _ : List[Int] => println("List of Ints")
case _ : List[String] => println("List of Strings")
case _ => println("Something else")
}
在运行时,被传递的List没有类型参数。 而List[Int]和List[String]都将会变成List[_]. 因此只有第一种情况会被调用。
你也可以在一定范围内不使用这种方法,而采用实验性的特性Manifest, 像这样:
def checkList[A](l: List[A])(implicit m: scala.reflect.Manifest[A]) = m.toString match {
case "int" => println("List of Ints")
case "java.lang.String" => println("List of Strings")
case _ => println("Something else")
}
7. 设计错误
Implicit关键字的使用不小心。Implicits非常强大,但要小心,普通类型不能使用隐式参数或者进行隐匿转换。
例如,下面一个implicit表达式:
implicit def string2Int(s: String): Int = s.toInt
这是一个不好的做法,因为有人可能错误的使用了一个字符串来代替Int。对于上面的这种情况,更好的方法是使用一个类。
case class Age(n: Int)
implicit def string2Age(s: String) = Age(s.toInt)
implicit def int2Age(n: Int) = new Age(n)
implicit def age2Int(a: Age) = a.n
这将会使你很自由的将Age与String或者Int结合起来,而不是让String和Int结合。类似的,当使用隐式参数时,不要像这样做:
case class Person(name: String)(implicit age: Int)
这不仅因为它容易在隐式参数间产生冲突,而且可能导致在毫无提示情况下传递一个隐式的age, 而接收者需要的只是隐式的Int或者其它类型。同样,解决办法是使用一个特定的类。
另一种可能导致implicit用法出问题的情况是有偏好的使用操作符。你可能认为”~”是字符串匹配时最好的操作符,而其他人可能会使用矩阵等价(matrix equivalence),分析器连接等(符号)。因此,如果你使用它们,请确保你能够很容易的分离其作用域。
8. 设计错误
设计不佳的等价方法。尤其是:
◆试着使用“==”代替“equals”(这让你可以使用“!=”)
◆使用这样的定义:
def equals(other: MyClass): Boolean
而不是这样的:
override def equals(other: Any): Boolean
◆忘记重载hashCode,以确保当a==b时a.hashCode==b.hashCode(反之不一定成立)。
◆不可以这样做交换: if a==b then b==a。特别地,当考虑子类化时,超类是否知道如何与一个子类进行对比,即使它不知道该子类是否存在。如果需要请查看canEquals的用法。
◆不可以这样做传递: if a==b and b ==c then a==c。
9. 用法错误
在Unix/Linux/*BSD的系统中,对你的主机进行了命名却没有在主机文件中声明。特别的,下面这条指令不会工作:
ping `hostname`
在这种情况下,fsc和scala都不会工作,而scalac则可以。这是因为fsc运行在背景模式下,通过TCP套接字监听连接来加速编译,而scala却用它来加快脚本的执行速度。
10.风格错误
使用while。虽然它有自己的用处,但大多数时候使用for往往更好。在谈到for时,用它们来产生索引不是一个好的做法。
避免这样的使用:
def matchingChars(string: String, characters: String) = {
var m = ""
for(i <- 0 until string.length)
if ((characters contains string(i)) && !(m contains string(i)))
m += string(i)
m
}
而应该使用:
def matchingChars(string: String, characters: String) = {
var m = ""
for(c <- string)
if ((characters contains c) && !(m contains c))
m += c
m
}
如果有人需要返回一个索引,可以使用下面的形式来代替按索引迭代的方法。如果对性能有要求,它可以较好的应用在投影(projection)(Scala 2.7)和视图(Scala 2.8)中。
def indicesOf(s: String, c: Char) = for {
(sc, index) <- s.zipWithIndex
if c == sc
免责声明:
来源于网络,仅用于分享知识,学习和交流!请下载完在24小时内删除。禁用于商业用途!如果您喜欢《Scala编程》,请购买正版,谢谢合作。
爱学习,请到3322软件站查找资源自行下载!
下载说明:
方法一:1、下载并解压,得出pdf文件
2、如果打不开本文件,别着急,这时候请务必在3322软件站选择一款阅读器下载哦
3、安装后,再打开解压得出的pdf文件
4、以上都完成后,接下来双击进行阅读就可以啦,朋友们开启你们的阅读之旅吧。
方法二:
1、可以在手机里下载3322软件站中的阅读器和百度网盘
2、接下来直接将pdf传输到百度网盘
3、用阅读器打开即可阅读
展开更多
scala编程 完整中文版 pdf下载地址
- 需先下载高速下载器:
- 专用下载:
- 其它下载: