[Перевод] Perl 6 и умное соответствие
Помните ли вы статью про оператор последовательностей в Perl 6? Последним аргументом он принимает ограничение, которое останавливает генерацию последовательности. К примеру
1, 2, 4 … 32; # 1 2 4 8 16 32 1, 2, 4 … * > 10; # 1 2 4 8 16 В первом случае используется числовое сравнение. Во втором запись * > 10 интерпретируется как замыкание → $x { $x > 10 }.
Оператор последовательностей выполняет «волшебное» сравнение в зависимости от типа соответствия. Это сравнение называется «умным соответствием» («smartmatching»), и эта концепция появляется во многих местах Perl 6. Примеры:
# после ключевого слова 'when': given $age { when 100 { say «Поздравляю!» } when * < 18 { say "Молодой ещё" } }
# после 'where': subset Even of Int where * %% 2;
# непосредственно с оператором smartmatch: if $input ~~ m/^\d+$/ { say »$input — целое число»; }
# аргументы для grep (), first () и т.д.: my @even = @numbers.grep: Even; С правой стороны от ~~ и после when и where сравниваемое значение берётся из $_. Это позволяет нам создавать конструкции, работающие с $_, такие, как регулярки, созданные через m/…/ и .method_call.
Примеры использования оператора:
# равен ли тип переменной Str? $foo ~~ Str # равно ли это 6? $foo ~~ 6 # или это «bar»? $foo ~~ «bar» # соответствует ли шаблону? $foo ~~ / \w+ '-' \d+ / # Находится ли между 15 и 25? $foo ~~ (15…25) # вызов замыкания $foo ~~ → $x { say 'ok' if 5 < $x < 25 } # Является ли это массивом из 6 элементов, у которого каждый нечётный элемент равен 1? $foo ~~ [1, *, 1, *, 1, *] Подробная таблица для оператора.
Заметьте, что в отличие от Perl 5, в Perl 6 smartmatching — единственный способ сравнить что-то с регуляркой, особого оператора для этого нет. Кроме того, хотя большинство операций smartmatching возвращает Bool, сравнение с регуляркой возвращает объект Match. Который, при этом, правильно ведёт себя в булевом контексте.
Ладненько, а как это использовать не со встроенными типами, а со своими собственными классами? Для этого надо написать особый метод, ACCEPTS. Допустим, есть у нас старый добрый класс Point:
class Point { has $.x; has $.y; method ACCEPTS (Positional $p2) { return $.x == $p2[0] and $.y == $p2[1] } } Понятно? Посмотрим, как это работает:
my $a = Point.new (x => 7, y => 9); say [3, 5] ~~ $a; # Bool: False say (7, 9) ~~ $a; # Bool: True Теперь Perl 6 может выполнять именно то, что вы имели в виду, даже с вашими собственными классами.