Введение в Scala.

С нуля до распределенных приложений.

Классы и объекты

Scala гибридный функциональный/ОО язык и обладает одним из самых мощных аппаратов по работе с классами и типами. Создатель языка, Мартин Одерски - автор generics в языке Java.

Синтаксис создания классов:

class MyClass extends SomeBaseClass { }

// создание объекта
new MyClass()

Тело класса является основным конструктором. Все поля и функции объявленные в нем являются членами объектов класса.

class Vector2D(x: Double, y: Double) {
  val length = Math.sqrt(x * x + y * y)

  println("Created class") // вызовется каждый раз при создании объекта
}

Дополнительные конструкторы объявляются функциями с названием this и должны вызывать основной конструктор:

class Vector2D(x: Double, y: Double) {
  val length = Math.sqrt(x * x + y * y)

  def this(l: Double) = this(l, 0)
}

Модификаторы доступа

В Scala доступны обычные модификаторы доступа для полей класса:

  • public, доступно всем клиентам класса
  • protected, доступно в классе и всем производным
  • private, доступно только объектам данного класса

Кроме того, модификаторы могут быть расширены квалификаторами [this] или [X]. Первый ограничивает доступ до одного объекта, второй делает поле видимым всем включающим классам или пакетам до X.

package mypackage {
  package subpackage {
    class MyClass {
      private val privateField = 1
      private[this] val morePrivateField = 2

      // видимо всем классам объектам внутри subpackage
      private[subpackage] val lessPrivateField = 3 

      def add(that: MyClass) = this.privateField + that.privateField

      // ошибка комплияции
      def addMore(that: MyClass) = this.morePrivateField + that.morePrivateField 
    }
  }
}

Модификаторы по умолчанию

Все поля классов по умолчанию имеют модификатор public.

Сделано это тех соображений, что Scala ориентирована на использование неизменяемых значений, поэтому “утечка” поля класса в интерфейс не дает возможности сломать программу, а только облегчает тестирование.

Параметры конструкторов имеют по умолчанию модификатор private[this]. Для превращения их в поле класса надо добавить в объявление ключевое слово val/var.

class MyClass(val x: Int, y: Int) { }

x - имеет модификатор public, y - имеет модификатор private[this]

Особый синтаксис

Несколько операций в Scala вызывают методы с определенным названием в классе. Оператор == вызванный на объекте класса вызывает метод equals, а ( ) метод apply.

class MyNumber(x: Double) {
  override def equals(other: Any) = true
  def apply() = println(x)
  def apply(n: Int) = println(x * n)
}

val n1 = new MyNumber(20.4)
println(n1 == 20) // true
n1()    // 20.4
n1(10)  // 204.0

Объекты-синглтоны

В Scala нет статических (static) методов, но есть особый синтаксис для создания объектов-синглтонов.

object MyObject {
  val myField = 1
  def myPrint = println(myField)
}

Этот объект будет создан в единственном экземпляре и доступен в любое время. Их можно использовать как объекты некоторого класса, для этого достаточно указать, что они унаследованы от него ключевым словом extends.

class MyNumber(val x: Int) {}
object MyZero extends MyNumber(0) {}

def printNumber(n: MyNumber) = {
  println(n.x)
}

printNumber(MyZero) // 0}

Объекты-компаньоны

Для каждого класса можно объявить специальный объект-компаньон (companion object). Это объект объявленный в том же файле и с тем же именем, что и класс. Этот объект имеет доступ к private полям класса.

Возможно вы уже встречались с созданием некоторых объектов без использования ключевого слова new. Здесь нет магии, это вызов метода apply на объекте-компаньоне.

class Person(val firstName: String, val middleName: String, val lastName: String) {}

object Person {
  def apply(firstName: String, lastName: String) = new Person(firstName, "", lastName)
  def apply(firstName: String) = new Person(firstName, "", "")
}

val p = Person("Tagir", "Magomedov")

Часто дополнительные конструкторы класса объявляют именно так.