Pattern Matching (сопоставление с образцом)
Оператор match
позволяет выполнить сопоставление значения с образцом.
x = 2
print match x {
case 1: "One"
case 2: "Two"
case "str": "String"
case _: "Unknown"
}
x = "str"
match x {
case "": {
println "Empty string"
}
case "str": {
println "String!"
}
}
Проверяется тип и значение. Если ни одна из веток case
не обнаружила совпадение, выполняется тело ветки case _
.
Помимо константных значений, в case
может присутствовать имя переменной.
def test(x) = match x {
case a: "case a: " + a
case b: "case b: " + b
case c: "case c: " + c
}
a = 10
b = 20
println test(15) // case c: 15
println test(20) // case b: 20
println test("test") // case c: test
В таком случае возможен один из двух сценариев:
- Переменная уже определена. Сравнивается её значение.
- Переменная не определена. Ей присваивается сопоставляемое значение и выполняется ветка
case
.
В примере выше, интерпретатор видит первые две ветки так:
case 10:
case 20:
Для последней ветки переменная c
не определена, поэтому выполнится присваивание c = x
, после чего вызов передаётся телу ветки case c
.
Уточнения
Ветка case
может иметь дополнительное сравнение
def test(x) = match x {
case x if x < 0: "(-∞ .. 0)"
case x if x > 0: "(0 .. +∞)"
case x: "0"
}
println test(-10) // (-∞ .. 0)
println test(0) // 0
println test(10) // (0 .. +∞)
Сопоставление массивов
Для сопоставления элементов массивов, в блоке case используется следующий синтаксис:
case []:
выполняется, если в массиве нет элементовcase [a]:
выполняется, если проверяемое значение - массив. В таком случае x будет содержать элементы массиваcase [a :: b]:
выполняется, если в массиве есть два и более элементовcase [a :: b :: c :: d :: e]:
выполняется, если в массиве есть пять и более элементов
Для двух последних случаев справедливы такие правила:
- Если количество переменных в списке совпадает с количество элементов массива, то всем переменным присваивается значение массива.
match [0, 1, 2] {
case [x :: y :: z]: // x = 0, y = 1, z = 2
}
- Если элементов массива больше, то в последней переменной будут сохранены оставшиеся элементы массива.
match [0, 1, 2, 3, 4] {
case [x :: y :: z]: // x = 0, y = 1, z = [2, 3, 4]
}
Пример рекурсивного вывода элементов массива
def arrayRecursive(arr) = match arr {
case [head :: tail]: "[" + head + ", " + arrayRecursive(tail) + "]"
case []: "[]"
case last: "[" + last + ", []]"
}
println arrayRecursive([1, 2, 3, 4, 5, 6, 7]) // [1, [2, [3, [4, [5, [6, [7, []]]]]]]]
Сопоставление значений массивов
Для сопоставления значений элементов массивов, используется синтаксис:
case (expr1, expr2, expr3):
выполняется, если в массиве есть 3 элемента и первый элемент равен результату выражения expr1, второй - результату expr2 и третий - результату expr3.case (expr1, _):
выполняется, если в массиве есть 2 элемента и первый элемент равен результату выражения expr1, а результат второго не важен.
Классическая задача FizzBuzz может быть решена с использованием Pattern Matching:
for i = 1, i <= 100, i++ {
println match [i % 3 == 0, i % 5 == 0] {
case (true, false): "Fizz"
case (false, true): "Buzz"
case (true, true): "FizzBuzz"
case _: i
}
}