В предыдущей части Учебника Perl мы познакомились со скалярами и узнали, как числа и строки конвертируются друг в друга на лету. Мы даже мельком взглянули на условное выражение if, но пока что не узнали, как сравнить два скаляра. Об этом пойдет речь в этой части.

Если у нас есть две переменные $x и $y, можно ли их сравнить? Равны ли 1, 1.0 и 1.00? А как насчет "1.00"? Что больше - "foo" или "bar"?

Два набора операторов сравнения

В Perl существует два набора операторов сравнения. Так же, как с уже изученными нами бинарными операторами сложения (+), конкатенации (.) и повторения (x), здесь тоже оператор определяет, как ведут себя операнды и как они сравниваются.

Вот эти два набора операторов:

Числовое   Строковое       Значение
==            eq           равно
!=            ne           не равно
<             lt           меньше
>             gt           больше
<=            le           меньше или равно
>=            ge           больше или равно

Операторы слева сравнивают числовые значения, а справа (в средней колонке) сравнивают значения, основываясь на ASCII таблице или на текущей локали.

Рассмотрим несколько примеров:

use strict;
use warnings;
use 5.010;

if ( 12.0 == 12 ) {
  say "TRUE";
} else {
  say "FALSE";
}

В этом простейшем случае Perl выведет TRUE, так как оператор == сравнивает два числа, так что Perl'у не важно, записаны ли они как целые числа, или как числа с плавающей точкой.

В следующем сравнении ситуация немного интереснее

"12.0" == 12

это выражение также истинно, ведь оператор Perl'а == конвертирует строку в число.

 2  < 3  истинно, так как < сравнивает два числа.

 2  lt 3 также истинно, ведь 2 находистя перед 3 в таблице ASCII.

12 > 3   очевидно, истинно.

12 gt 3  вернет FALSE

Возможно, с первого взгляда кому-то это покажется неожиданным, но если подумать, Perl ведь сравнивает строки посимвольно. Так что он сравнивает "1" и "3", и раз они отличаются и "1" стоит перед "3" в таблице ASCII, на этом этапе Perl решает, строковое значение 12 меньше, чем строковое значение 3.

Всегда нужно быть уверенным, что сравниваешь значение именно так, как нужно!

"foo"  == "bar" будет истинно

Также это выдаст предупреждение, если(!) предупреждения включены с помощью use warnings. Причина его в том, что мы используем две строки как числа в числовом сравнении ==. Как упоминалось в предыдущей части, Perl смотрит на строку, начиная с левого конца, и конвертирует ее в число, которое там находит. Поскольку обе строки начинаются с букв, они будут конвертированы в 0. 0 == 0, так что выражение истинно.

С другой стороны:

"foo"  eq "bar"  ложно

Так что всегда нужно быть уверенным, что сравниваешь значение именно так, как нужно!

То же будет при сравнении

"foo"  == "" будет истинно

и

"foo"  eq "" будет ложно

Результаты в этой таблице могут пригодиться:

 12.0   == 12    ИСТИНА
"12.0"  == 12    ИСТИНА
"12.0"  eq 12    ЛОЖЬ
  2     <   3    ИСТИНА
  2    lt   3    ИСТИНА
 12     >   3    ИСТИНА
 12    gt   3    ЛОЖЬ ! (внимание, может быть неочевидно с первого взгляда)
"foo"  ==  ""    ИСТИНА  ! (Выдает предупреждение, если использована прагма "warnings")
"foo"  eq  ""    ЛОЖЬ
"foo"  == "bar"  ИСТИНА  ! (Выдает предупреждение, если использована прагма "warnings")
"foo"  eq "bar"  ЛОЖЬ

И наконец пример, когда можно попасть в ловушку, получив некоторые данные от пользователя, и, аккуратно отрезав перевод строки в конце, проверить, не является ли строка пустой.

use strict;
use warnings;
use 5.010;

print "input: ";
my $name = <STDIN>;
chomp $name;

if ( $name == "" ) {   # неверно! здесь нужно использовать eq вместо == !
  say "TRUE";
} else {
  say "FALSE";
}

Если запустить этот скрипт и ввести "abc", мы получим ответ TRUE, так как perl решил, что "abc" это то же, что и пустая строка.