Сопоставление с образцом в Scala

Scala предоставляет мощный механизм сопоставления с образцом, и он также широко используется.

Сопоставление с образцом содержит ряд альтернатив, каждая из которых начинается с ключевого словаcase. Каждая альтернатива содержит образец и одно или несколько выражений. Символ стрелки=>разделяет образец и выражения.

Ниже приведён простой пример сопоставления с образцом для целочисленного значения:

Пример

object Test {
   def main(args: Array[String]) {
      println(matchTest(3))

   }
   def matchTest(x: Int): String = x match {
      case 1 => "one"
      case 2 => "two"
      case _ => "many"
   }
}

Выполнение приведенного выше кода дает следующий вывод:

$ scalac Test.scala 
$ scala Test
many

match соответствует switch в Java, но пишется после выражения-селектора. То есть:selector match { alternatives }.

Выражение match вычисляется путём проверки каждого шаблона в порядке, записанном в коде. Как только находится совпадающий case, остальные case больше не проверяются.

Далее рассмотрим пример сопоставления с образцом для различных типов данных:

Пример

object Test {
   def main(args: Array[String]) {
      println(matchTest("two"))
      println(matchTest("test"))
      println(matchTest(1))
      println(matchTest(6))

   }
   def matchTest(x: Any): Any = x match {
      case 1 => "one"
      case "two" => 2
      case y: Int => "scala.Int"
      case _ => "many"
   }
}

Выполнение приведенного выше кода дает следующий вывод:

$ scalac Test.scala 
$ scala Test
2
many
one
scala.Int

В примере первый case соответствует целочисленному значению 1, второй case соответствует строковому значению two, а третий case соответствует шаблону типа, используемому для определения, является ли переданное значение целым числом. По сравнению с использованием isInstanceOf для определения типа, использование сопоставления с образцом лучше. Четвёртый case представляет вариант полного совпадения по умолчанию, то есть элемент match, когда не найдено других совпадений, аналогично default в switch.


Использование case-классов

Определение класса, использующее ключевое слово case, — это case-класс. Case-классы — это особый вид классов, оптимизированный для сопоставления с образцом.

Ниже приведён простой пример case-класса:

Пример

object Test {
   def main(args: Array[String]) {
        val alice = new Person("Алиса", 25)
        val bob = new Person("Боб", 32)
        val charlie = new Person("Чарли", 32)
   
    for (person <- List(alice, bob, charlie)) {
        person match {
            case Person("Алиса", 25) => println("Привет, Алиса!")
            case Person("Боб", 32) => println("Привет, Боб!")
            case Person(name, age) =>
               println("Возраст: " + age + " лет, имя: " + name + "?")
         }
      }
   }
   // Case-класс
   case class Person(name: String, age: Int)
}

Выполнение приведенного выше кода дает следующий вывод:

$ scalac Test.scala 
$ scala Test
Hi Alice!
Hi Bob!
Age: 32 year, name: Charlie?

Когда объявляется case class, автоматически происходит следующее:

  • Каждый параметр конструктора становится val, если только он явно не объявлен как var, но это не рекомендуется;
  • В сопутствующем объекте предоставляется метод apply, поэтому объекты можно создавать без использования ключевого слова new;
  • Предоставляется метод unapply, чтобы работало сопоставление с образцом;
  • Методы toString, equals, hashCode и copy генерируются, если эти методы не определены явно.
Другие расширения