Tour of Scala

Основы

Language

На этой странице мы расскажем об основах Scala.

Попробовать Scala в браузере.

Вы можете запустить Scala в браузере с помощью Scastie.

  1. Зайдите на Scastie.
  2. Вставьте println("Hello, world!") в левую панель.
  3. Нажмите кнопку “Run”. Вывод отобразится в правой панели.

Это простой способ поэкспериментировать со Scala кодом без всяких настроек.

Большинство примеров кода в этой документации также интегрированы с Scastie, поэтому вы можете поэкспериментировать с ними, просто нажав кнопку Run.

Выражения

Выражения — это вычислимые утверждения.

1 + 1

Вы можете выводить результаты выражений, используя println.

println(1) // 1
println(1 + 1) // 2
println("Hello!") // Hello!
println("Hello," + " world!") // Hello, world!

Значения

Результаты выражений можно присваивать именам с помощью ключевого слова val.

val x = 1 + 1
println(x) // 2

Названные результаты, такие как x в примере, называются значениями. Вызов значения не приводит к его повторному вычислению.

Значения не изменяемы и не могут быть переназначены.

x = 3 // Не компилируется.

Типы значений могут быть выведены автоматически, но можно и явно указать тип, как показано ниже:

val x: Int = 1 + 1

Обратите внимание, что объявление типа Int происходит после идентификатора x, следующим за :.

Переменные

Переменные похожи на значения константы, за исключением того, что их можно присваивать заново. Вы можете объявить переменную с помощью ключевого слова var.

var x = 1 + 1
x = 3 // Компилируется потому что "x" объявлен с ключевым словом "var".
println(x * x) // 9

Как и в случае со значениями, вы можете явно указать тип, если захотите:

var x: Int = 1 + 1

Блоки

Вы можете комбинировать выражения, окружая их {}. Мы называем это блоком.

Результат последнего выражения в блоке будет результатом всего блока в целом.

println({
  val x = 1 + 1
  x + 1
}) // 3

Функции

Функции — это выражения, которые принимают параметры.

Вы можете определить анонимную функцию (т.е. без имени), которая возвращает переданное число, прибавив к нему единицу:

(x: Int) => x + 1

Слева от => находится список параметров. Справа — выражение, связанное с параметрами.

Вы также можете назвать функции.

val addOne = (x: Int) => x + 1
println(addOne(1)) // 2

Функции могут принимать множество параметров.

val add = (x: Int, y: Int) => x + y
println(add(1, 2)) // 3

Или вообще не принимать никаких параметров.

val getTheAnswer = () => 42
println(getTheAnswer()) // 42

Методы

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

Методы задаются ключевым словом def. За def следует имя, список параметров, возвращаемый тип и тело.

def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3

Обратите внимание, как объявлен возвращаемый тип сразу после списка параметров и двоеточия : Int.

Методы могут принимать несколько списков параметров.

def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9

Или вообще ни одного списка параметров.

def name: String = System.getProperty("user.name")
println("Hello, " + name + "!")

Есть некоторые отличия от функций, но пока что их можно рассматривать как нечто похожее.

Методы также могут иметь многострочные выражения.

def getSquareString(input: Double): String = {
  val square = input * input
  square.toString
}
println(getSquareString(2.5)) // 6.25
def getSquareString(input: Double): String =
  val square = input * input
  square.toString

println(getSquareString(2.5)) // 6.25

Последнее выражение в теле становится возвращаемым значением метода (у Scala есть ключевое слово return, но оно практически не используется).

Классы

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

class Greeter(prefix: String, suffix: String) {
  def greet(name: String): Unit =
    println(prefix + name + suffix)
}
class Greeter(prefix: String, suffix: String):
  def greet(name: String): Unit =
    println(prefix + name + suffix)

Возвращаемый тип метода greet это Unit, используется тогда, когда не имеет смысла что-либо возвращать. Аналогично void в Java и C. Поскольку каждое выражение Scala должно иметь какое-то значение, то при отсутствии возвращающегося значения возвращается экземпляр типа Unit. Явным образом его можно задать как (), он не несет какой-либо информации.

Вы можете создать экземпляр класса, используя ключевое слово new.

val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
val greeter = Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!

Позже мы рассмотрим классы подробнее.

Классы-образцы (Case Class)

В Scala есть специальный тип класса, который называется классом-образцом (case class). По умолчанию такие классы неизменны и сравниваются по значению из конструктора. Вы можете объявлять классы-образцы с помощью ключевых слов case class.

case class Point(x: Int, y: Int)

Можно создавать экземпляры класса-образца без использования ключевого слова new.

val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)

Они сравниваются по значению.

if (point == anotherPoint) {
  println(s"$point and $anotherPoint are the same.")
} else {
  println(s"$point and $anotherPoint are different.")
} // Point(1,2) и Point(1,2) одни и те же.

if (point == yetAnotherPoint) {
  println(s"$point and $yetAnotherPoint are the same.")
} else {
  println(s"$point and $yetAnotherPoint are different.")
} // Point(1,2) и Point(2,2) разные.
if point == anotherPoint then
  println(s"$point and $anotherPoint are the same.")
else
  println(s"$point and $anotherPoint are different.")
// Point(1,2) и Point(1,2) одни и те же.

if point == yetAnotherPoint then
  println(s"$point and $yetAnotherPoint are the same.")
else
  println(s"$point and $yetAnotherPoint are different.")
// Point(1,2) и Point(2,2) разные.

Есть еще много деталей, которые мы бы хотели рассказать про классы-образцы; мы уверены, что вы влюбитесь в них! Обязательно рассмотрим их позже.

Объекты

Объекты задаются и существуют в единственном экземпляре. Вы можете думать о них как об одиночках (синглтонах) своего собственного класса.

Вы можете задать объекты при помощи ключевого слова object.

object IdFactory {
  private var counter = 0
  def create(): Int = {
    counter += 1
    counter
  }
}
object IdFactory:
  private var counter = 0
  def create(): Int =
    counter += 1
    counter

Вы можете сразу получить доступ к объекту, ссылаясь на его имя.

val newId: Int = IdFactory.create()
println(newId) // 1
val newerId: Int = IdFactory.create()
println(newerId) // 2

Позже мы рассмотрим объекты подробнее.

Трейты

Трейты — как типы описывают характеристики классов, в нем могут объявляться определенные поля и методы. Трейты можно комбинировать.

Объявить трейт можно с помощью ключевого слова trait.

trait Greeter {
  def greet(name: String): Unit
}
trait Greeter:
  def greet(name: String): Unit

Трейты также могут иметь реализации методов и полей, которые предполагается использовать умолчанию.

trait Greeter {
  def greet(name: String): Unit =
    println("Hello, " + name + "!")
}
trait Greeter:
  def greet(name: String): Unit =
    println("Hello, " + name + "!")

Вы можете наследовать свойства трейтов, используя ключевое слово extends и переопределять реализацию с помощью ключевого слова override.

class DefaultGreeter extends Greeter

class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
  override def greet(name: String): Unit = {
    println(prefix + name + postfix)
  }
}

val greeter = new DefaultGreeter()
greeter.greet("Scala developer") // Hello, Scala developer!

val customGreeter = new CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?
class DefaultGreeter extends Greeter

class CustomizableGreeter(prefix: String, postfix: String) extends Greeter:
  override def greet(name: String): Unit =
    println(prefix + name + postfix)

val greeter = DefaultGreeter()
greeter.greet("Scala developer") // Hello, Scala developer!

val customGreeter = CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?

Здесь DefaultGreeter наследуется только от одного трейта, но можно наследоваться от нескольких.

Позже мы рассмотрим трейты подробнее.

Главный метод

Главный метод является отправной точкой в программе. Для Виртуальной Машины Java требуется, чтобы главный метод назывался main и принимал один аргумент, массив строк.

Используя объект, можно задать главный метод следующим образом:

In Scala 2 you must define a main method manually. Using an object, you can define the main method as follows:

object Main {
  def main(args: Array[String]): Unit =
    println("Hello, Scala developer!")
}

In Scala 3, with the @main annotation, a main method is automatically generated from a method as follows:

@main def hello() = println("Hello, Scala developer!")

Дополнительные ресурсы

Contributors to this page: