返回首页 Scala 课堂

Scala 课堂:基础(四)

这里我们转载 Twitter 的 Scala 课堂 ,转载的内容基本来自Twitter的Scala课堂中文翻译,部分有小改动.

apply 方法

当类或对象有一个主要用途的时候,apply 方法为你提供了一个很好的简洁的语法结构。


scala>  class Foo {}
defined class Foo

scala> object FooMaker {
     |  def apply() = new Foo
     | }
defined object FooMaker

scala> val newFoo =FooMaker()
newFoo: Foo = Foo@333038c7

或者:


scala> class Bar {
     |  def apply() =0
     | }
defined class Bar

scala>  val bar = new Bar
bar: Bar = Bar@706ba7cf

scala> bar()
res0: Int = 0

在这里,我们实例化对象看起来像是在调用一个方法。以后会有更多介绍!

单例对象

单例对象用于持有一个类的唯一实例。通常用于工厂模式。


object Timer {
  var count = 0

  def currentCount(): Long = {
    count += 1
    count
  }
}

可以这样使用:


scala> Timer.currentCount()
res1: Long = 1

单例对象可以和类具有相同的名称,此时该对象也被称为“伴生对象”。我们通常将伴生对象作为工厂使用。

下面是一个简单的例子,可以不需要使用’new’来创建一个实例了。


class Bar(foo: String)

object Bar {
  def apply(foo: String) = new Bar(foo)
}

函数即对象

在 Scala 中,我们经常谈论对象的函数式编程。这是什么意思?到底什么是函数呢?

函数是一些特质的集合。具体来说,具有一个参数的函数是 Function1 特质的一个实例。这个特征定义了 apply() 语法糖,让你调用一个对象时就像你在调用一个函数。


object addOne extends Function1[Int, Int] {
     def apply(m: Int): Int = m + 1
}

defined object addOne

scala> addOne(1)
res2: Int = 2

这个 Function 特质集合下标从0开始一直到22。为什么是22?这是一个主观的魔幻数字(magic number)。我从来没有使用过多于22个参数的函数,所以这个数字似乎是合理的。
apply 语法糖有助于统一对象和函数式编程的二重性。你可以传递类,并把它们当做函数使用,而函数本质上是类的实例。 这是否意味着,当你在类中定义一个方法时,得到的实际上是一个 Function 的实例?不是的,在类中定义的方法是方法而不是函数。在 repl 中独立定义的方法是 Function 的实例。 类也可以扩展 Function,这些类的实例可以使用()调用。


 class AddOne extends Function1[Int, Int] {
    def apply(m: Int): Int = m + 1
}

defined class AddOne

scala> val plusOne = new AddOne()
plusOne: AddOne = <function1>

scala> plusOne(1)
res3: Int = 2

可以使用更直观快捷的 extends (Int => Int) 代替 extends Function1[Int, Int]


class AddOne extends (Int => Int) {
  def apply(m: Int): Int = m + 1
}

你可以将代码组织在包里。


package com.twitter.example

在文件头部定义包,会将文件中所有的代码声明在那个包中。 值和函数不能在类或单例对象之外定义。单例对象是组织静态函数(static function)的有效工具。


package com.twitter.example

object colorHolder {
  val BLUE = "Blue"
  val RED = "Red"
}

现在你可以直接访问这些成员


println("the color is: " + com.twitter.example.colorHolder.BLUE)