Scala学习笔记二

来源:互联网 发布:刺客信条优化最好的 编辑:程序博客网 时间:2024/04/29 11:12

第四章 类和对象

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输出gscala> println(g)//输出结果()//定义一个带“=”的函数scala> def f() = {"hello world"}//编译结果f: ()String//使用println输出fscala> println(f)//输出结果hello world

4.2 分号推断

  Scala程序里,语句末尾的分号通常是可选的。如果你愿意可以输入一个,但若一行里仅有一个语句也可不写。另一方面,如果一行里写多个语句那么分号是需要的

4.3 Singleton对象

  scala中没有静态成员,取而代之的是单例对象Singleton Object,使用object关键字来定义。
  伴生对象与伴生类:若某个单例对象和某个类共享同一个名称,那么这个单例对象称为这个类的伴生对象,这个类被称为这个对象的伴生类。类和它的伴生对象可以相互访问其私有成员。
  有如下代码:

import scala.collection.mutable.Mapobject 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特质。

0 0
原创粉丝点击