match: сопоставление с образцом

Если if/else — это вилка, то match — целая развязка дорог, и каждая ведёт к своему результату.

«Паттерн-матчинг превращает разбор данных из лестницы условий в наглядную таблицу вариантов.»

Выражение match сопоставляет значение с набором образцов и выполняет ветку первого подошедшего. В отличие от switch в других языках, match — это выражение: оно возвращает значение.

def describe(n: Int): String =
  n match
    case 0 => "ноль"
    case 1 => "один"
    case _ => "много"   // _ — образец по умолчанию

println(describe(0))   // ноль
println(describe(42))  // много

Подчёркивание _ — это «всё остальное», аналог default. Поскольку match возвращает значение, результат можно сразу присвоить.

Сопоставление по типу

match умеет проверять тип значения и сразу давать к нему доступ под именем.

def kind(x: Any): String =
  x match
    case s: String => s"строка длиной ${s.length}"
    case i: Int    => s"число $i"
    case _         => "что-то ещё"

println(kind("привет"))  // строка длиной 6
println(kind(99))        // число 99

Условия в образцах (guards)

К образцу можно добавить условие через if — это называется охранник (guard).

def sign(n: Int): String =
  n match
    case x if x > 0 => "положительное"
    case 0         => "ноль"
    case _         => "отрицательное"

println(sign(-5))  // отрицательное

Та же идея на Python ▶

# В Python 3.10+ есть match (structural pattern matching)
def describe(n):
    match n:
        case 0:
            return "ноль"
        case 1:
            return "один"
        case _:
            return "много"

def sign(n):
    match n:
        case x if x > 0:
            return "положительное"
        case 0:
            return "ноль"
        case _:
            return "отрицательное"

print(describe(0))   # ноль
print(sign(-5))      # отрицательное
value match
   case образец1 -> результат1
   case образец2 -> результат2
   case _        -> результат по умолчанию
            |
   первый подошедший образец выигрывает

Как работает под капотом (JVM)

Компилятор Scala превращает match в цепочку проверок и переходов в байт-коде. Для простых случаев (числа, строки) он может использовать эффективную инструкцию tableswitch/lookupswitch JVM — ту же, что и switch в Java. Для проверок по типу генерируются instanceof и приведения. Образцы проверяются сверху вниз, поэтому порядок имеет значение: более частные образцы должны идти раньше общих.

Частые ошибки

  • Поставить case _ слишком рано. Он перехватит всё, и образцы ниже никогда не сработают.
  • Забыть про match как выражение. Не нужно return в каждой ветке — результат и так возвращается.
  • Перепутать литерал и переменную. Имя со строчной буквы в образце создаёт новую переменную, а не сравнивает с существующей.

Best practices

  • Ставьте частные образцы выше, общий case _ — в конце.
  • Используйте guards (if) для условий, которые трудно выразить образцом.
  • Предпочитайте match длинным цепочкам if/else if — он читаемее.

Паттерн-матчинг как способ читать данные

Паттерн-матчинг — пожалуй, самая узнаваемая черта Scala. Он заменяет не только switch, но и длинные лестницы if/else, проверки типов с приведением и ручной разбор структур. Вместо того чтобы спрашивать «а это такой тип? а извлеки-ка поле?», вы описываете форму данных, которую ожидаете, а компилятор сам проверяет и извлекает. Код становится похож на таблицу: слева — форма, справа — что с ней делать.

То, что match является выражением, имеет глубокие последствия. Каждая ветка возвращает значение, поэтому результат сразу можно присвоить или вернуть из метода. Это исключает целый класс ошибок, типичных для switch в других языках: забытый break, проваливание между ветками, случайно неинициализированная переменная. В Scala каждый случай — это полноценное выражение со своим результатом.

По мере практики вы заметите, что многие задачи естественно формулируются как «разбор по случаям», и паттерн-матчинг становится первым инструментом, к которому тянется рука. Это нормально и идиоматично. Главное — следить за порядком образцов и держать общий случай в конце, чтобы частные ветки успевали сработать раньше универсальной.

Итоги. match — выражение, сопоставляющее значение с образцами по литералам, типам и условиям, и возвращающее результат. Дальше — case-классы, которые раскрывают всю мощь паттерн-матчинга.

Проверьте себя
1. Чем match в Scala отличается от switch в большинстве языков?
AРаботает только с числами
BЭто выражение, которое возвращает значение
CТребует break после каждой ветки
DМожет проверять только равенство
2. Что означает образец case _ в match?
AПустую ветку
BСовпадение с любым значением (по умолчанию)
CОшибку
DСравнение с нулём