Есть несколько способов сравнения объектов в Perl. Можно проверить равенство значений используя инфиксный оператор ===. Для неизменных (immutable) объектов ( значения которых нельзя изменить, литералов. Например литерал 7 всегда будет 7) это обычное сравнение значений. Например 'hello'==='hello' всегда верно потому, что обе строки неизменны и имеют одинаковое значение.
Для изменяемых объектов === сравнивает их идентичность. === возвращает истину, если его аргументы являются псевдонимами одного и того же объекта. Или же двое объектов идентичны, если это один и тот же объект. Даже если оба массива @a и @b содержат одинаковые значения, если их контейнеры разные объекты, они будут иметь различные идентичности и не будут тождественны при сравнении ===:
my @a = 1, 2, 3;
my @b = 1, 2, 3;
say @a === @a; # 1
say @a === @b; # 0
# здесь используется идентичность
say 3 === 3; # 1
say 'a' === 'a'; # 1
my $a = 'a';
say $a === 'a'; # 1
Оператор eqv возвращает Истина если два объекта одного типа и одинаковой структуры. Так для @a и @b указанных в примере, @a eqv @b истинно потому, что @a и @b содержат одни и те же значения. С другой стороны '2' eqv 2 вернет False, так как аргумент слева строка, а справа - число, и таким образом они разных типов.
Вы можете узнать, равны ли числовые значения двух объектов с помощью инфиксного оператора ==. Если один из объектов не числовой, Perl произведет его преобразование в число перед сравнением. Если не будет подходящего способа преобразовать объект в число, Perl будет использовать 0 в качестве значения.
say 1 == 1.0; # 1
say 1 == '1'; # 1
say 1 == '2'; # 0
say 3 == '3b' # 1
Операторы <, <=, >=, и > - являются числовыми операторами сравнения и возвращают логическое значение сравнения. != возвращает True (Истина), если числовые значения объектов различны.
Если сравниваются списки или массивы,то вычисляется количество элементов в списке.
my @colors = <red blue green>;
if @colors == 3 {
say "It's true, @colors contains 3 items";
}
Так же как == преобразует свои аргументы в числа, инфиксный оператор eq сравнивает равенство строк, преобразуя аргументы в строки при необходимости.
if $greeting eq 'hello' {
say 'welcome';
}
Другие операторы сравнивают строки лексикографически.
Таблица 3.2. Операторы и сравнения
| Числовые | Строковые | Значение |
|---|---|---|
| == | eq | равно (equals) |
| != | ne | не равно (not equal) |
| !== | !eq | не равно (not equal) |
| < | lt | меньше чем ( less than ) |
| <= | le | меньше или равно (less or equal) |
| > | gt | больше чем ( greater than ) |
>= | ge | больше или равно ( greater or equal ) |
Например, 'a' lt 'b' вернет истину, так же как 'a' lt 'aa'.
!= на самом деле более удобная форма для !==, который в свою очередб представляет собой объединеие метаоператора ! и инфиксного оператора ==. Такое же обяснение приминительно к ne и !eq.
Операторы three-way сравнения получают два операнда и возвращают Order::Increase, если операнд слева меньше, Order::Same - если равны, Order::Decrease - если операнд справа меньше (Order::Increase, Order::Same и Order::Decrease являются перечислениями ( enums ); см. ). Для числовых сравнений используется оператор <=>, а для строковых это leg (от англ. lesser, equal, greater). Инфиксный оператор cmp также является оператором сравнения, возвращающий три результата сравнения. Его особенность в том, что он зависит от типа аргументов: числа сравнивает как <=>, строки как leg и ( например) пары сначала сравнивая ключи, а затем значения (если ключи равны).
say 10 <=> 5; # +1
say 10 leg 5; # because '1' lt '5'
say 'ab' leg 'a'; # +1, lexicographic comparison
Типичным применением упомянутых three-way операторов сравнения является сортировка. Метод .sort в списках получает блок или функцию, которые сравнивают свои два аргумента и возвращают значения отрицательные если меньше, 0 - если аргументы равны и больше 0, если первый аргумент больше второго. Эти результаты затем используются при сортировке для формирования результата.
say ~<abstract Concrete>.sort;
# output: Concrete abstract
say ~<abstract Concrete>.sort:
-> $a, $b { uc($a) leg uc($b) };
# output: abstract Concrete
По умолчанию используется сортировка чувствительная к регистру, т.е. символы в верхнем регистре "больше" символов в нижем. В примере используется сортировка без учета регистра.
Разные операторы сравнения приводит свои аргументы к определённым типам перед сравнением их. Это полезно, когда требуется конкретное сравнение, но типы параметров неизвестны. Perl 6 предоставляет особый оператор который позволяет производить сравнение "Делай Как Надо" (Do The Right Thing ) с помощью ~~ - оператора "умного" сравнения.
if $pints-drunk ~~ 8 {
say "Go home, you've had enough!";
}
if $country ~~ 'Sweden' {
say "Meatballs with lingonberries and potato moose, please."
}
unless $group-size ~~ 2..4 {
say "You must have between 2 and 4 people to book this tour.";
}
Оператор "умного" сопоставления всегда решает какого рода сравнение производить в зависимости от типа значения в правой части. В предыдущих примерах эти сравнения были числовым, строковым и сравнением диапазонов соответственно. В данной главе была продемонстрирована работа операторов сравнения: чисел - == и строк eq.Однако нет оператора для сравнения диапазонов. Это является частью возможностей "умного" сопоставления: более сложные типы позволяют реализовывать необычные идеи сочетая сравнения их с другими.
"Умное" сопоставление работает, вызывая метод ACCEPTS у правого операнда и передавая ему операнд слева как аргумент. Выражение $answer ~~ 42 сводится к вызову 42.ACCEPTS($answer). Данная информация пригодится, когда вы прочитаете последующие главы, посвященные классам и методам. Вы тоже напишите вещи, которые смогут производить "умное" сопоставление, реализовав метод ACCEPTS для того, чтобы "работало как надо".