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-классы, которые раскрывают всю мощь паттерн-матчинга.