Scala学习笔记二
2015-07-02 09:18
330 查看
第四章 类和对象
4.1 类,字段和方法
假设有这样的类:class ChecksumAccumulator { private var sum = 0 def add(b: Byte): Unit = { sum += b } def checksum(): Int = { return -(sum & 0xFF) + 1 } }
由于函数体只有一句话,因此可以去掉外面的大括号;另外,checksum方法最后的return语句是多余的可以去掉。如果没有发现任何显式的返回语句,Scala方法将返回方法中最后一个计算得到的值。将代码简化成如下所示:
class ChecksumAccumulator { private var sum = 0 def add(b: Byte): Unit = sum += b def checksum(): Int = -(sum & 0xFF) + 1 }
由于add方法的结果类型为Unit,执行的目的就是它的副作用。例如add的副作用就是sum被重新赋值了。这种情况下可以去掉等号和结果类型,把方法放在大括号里,如下所示:
class ChecksumAccumulator { private var sum = 0 def add(b: Byte) { sum += b } def checksum(): Int = -(sum & 0xFF) + 1 }
注意,如果没写结果类型,但是写了“=”,那么编译器会根据最后返回值的类型确定函数结果类型;若是去掉了结果类型和“=”,那么函数的结果类型一定为Unit。
scala能将任何类型转换为Unit,但是转换后原来的值就丢失了。看下面的例子
//定义一个不带“=”的函数 scala> def g() {"hello world"} //编译结果 g: ()Unit //使用println输出g scala> println(g) //输出结果 () //定义一个带“=”的函数 scala> def f() = {"hello world"} //编译结果 f: ()String //使用println输出f scala> println(f) //输出结果 hello world
4.2 分号推断
Scala程序里,语句末尾的分号通常是可选的。如果你愿意可以输入一个,但若一行里仅有一个语句也可不写。另一方面,如果一行里写多个语句那么分号是需要的4.3 Singleton对象
scala中没有静态成员,取而代之的是单例对象Singleton Object,使用object关键字来定义。伴生对象与伴生类:若某个单例对象和某个类共享同一个名称,那么这个单例对象称为这个类的伴生对象,这个类被称为这个对象的伴生类。类和它的伴生对象可以相互访问其私有成员。
有如下代码:
import scala.collection.mutable.Map object ChecksumAccumulator { private val cache = Map[String, Int]() def calculate(s: String): Int = if (cache.contains(s)) cache(s) else { val acc = new ChecksumAccumulator for (c <- s) acc.add(c.toByte) val cs = acc.checksum() cache +=(s -> cs) cs } }
这个object和上一小节定义的类同名,因此为该类的伴生对象,可以访问其中的私有成员变量和方法。
该对象有一个名为cache的私有成员变量,以及一个名为calculate的方法。在calculate方法中对于传入的String类型的参数s,首先判断cache中是否存在,若存在则返回该key对应的value;若不存在,则创建一个ChecksumAccumulator对象,调用该对象的add()方法和checksum()方法,最后将结果存入到cache中。
单例对象中的方法可以使用“类名.方法名”来直接调用,而不用new一个对象。类可以带参数,但单例对象不带参数(没法通过new来实例化单例对象)。
单例对象会在第一次被访问的时候初始化。
在java里类名必须和文件名相同,但在scala里却不一定。
注意:也有的object并没有共享名称的类,这类单例对象称为“孤立对象”。使用场景:把相关的功能收集在一起(如将某一类的transfer功能都放到某个object中)或定义一个scala应用的入口(如在object里写一个main()方法成为应用的入口)
4.4 Scala的Application特质
有如下代码:import ChecksumAccumulator.calculate object FallWinterSpringSummer extends Application { for (season <- List("fall", "winter", "spring")) println(season +": "+ calculate(season)) }
通过继承Application,可以不用写main方法,而是直接在大括号里写方法体就,然后直接点击运行就可以被运行。
原理:Trait Application声明了带有合适的签名的main方法,并由上面的单例对象继承,使它可以像个Scala程序那样用。大括号之间的代码被收集进了单例对象的主构造器,并在类被初始化时被执行。
继承自Application比写个显式的main方法要短,不过它也有些缺点。首先,如果想访问命令行参数的话就不能用它,因为args数组不可访问。第二,因为某些JVM线程模型里的局限,如果程序是多线程的就需要显式的main方法。最后,对于某些JVM,Application中执行的对象的初始化代码并不会被优化。因此只有当你的程序相对简单和单线程情况下你才可以继承Application特质。
相关文章推荐
- Windows7下安装Scala 2.9.2教程
- XML 文件解析--含Unicode字符的XML文件
- 分分钟掌握快速排序(Java / Scala 实现)
- Scala极速入门
- Spark初探
- Scala实现REST操作
- Scala method call syntax
- 关于Scala多重继承的菱形问题
- Scala 高阶函数(high-order function)剖析
- Spray.io搭建Rest服务
- Spray.io搭建Rest — 支持Twirl模板并部署
- 搭建hadoop/spark集群环境
- ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架
- 用Scala实现延迟计算
- SBT学习 [持续更新...]
- Scala创建新的控制结构
- Scala: 一次命令式到函数式的重构
- 浅谈Scala的特质(trait)
- 浅谈Scala 2.8的包对象(package object)