Представьте, что, составляя список покупок, пишете на листке

"2 буханки хлеба"

и отдаете его своей второй половине, которая тут же выбрасывает ошибку неправильного перевода типов прямо вам в лицо. Ведь, действительно, "2" здесь - это строка, а не число.

Это было бы то еще разочарование, не правда ли?

Перевод типов в Perl

В большинсте языков программирования тип операнда определяет поведение оператора. То есть прибавление одного числа к другому выполнится как числовое сложение, а прибавление двух строк - как конкатенация. Это свойство называется перегрузкой операторов.

Perl по большей части работает наоборот.

В Perl оператор определяет, как будут использоваться операнды.

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

C-программисты, должно быть, назовут эти преобразования приведением типов, но это выражение не используется в мире Perl. Возможно, потому, что все происходит само собой.

Для Perl'а не важно, пишете вы что-то как строку или как число. Он конвертирует их друг в друга автоматически, основываясь на контексте.

Преобразование

число => строка

это просто. Мы просто представляем, что вокруг числа появляются кавычки "".

Преобразование

строка => число

может немного озадачить. Если строка выглядит для perl'а как число, то все просто. Числовое значение будет тем же самым, только без кавычек.

Если же встречается символ, который не дает perl'у полностью превратить строку в число, то он использует как число столько, сколько сможет, из левой части строки, и проигнорирует остальное.

Позвольте продемонстрировать вам пару примеров:

Исходное значение   Строка   Число

       42           "42"      42
       0.3          "0.3"     0.3
       "42"         "42"      42
       "0.3"        "0.3"     0.3

       "4z"         "4z"      4        (*)
       "4z3"        "4z3"     4        (*)
       "0.3y9"      "0.3y9"   0.3      (*)
       "xyz"        "xyz"     0        (*)
       ""           ""        0        (*)
       "23\n"       "23\n"    23

Во всех случаях, когда перевод строки в число не полон, кроме последнего, perl выдаст предупреждение. Ну, предполагается, что вы включили use warnings в соответствии с рекомендациями.

Пример

Теперь давайте посмотрим в коде то, что вы видели в таблице:

use strict;
use warnings;

my $x = "4T";
my $y = 3;

Конкатенация превращает оба значения в строки:

print $x . $y;    # 4T3

Сложение превращает оба значения в числа:

print $x + $y;  # 7
                # Argument "4T" isn't numeric in addition (+) at ...

Argument isn't numeric

Это предупреждение, которое вы получите, когда perl попытается конвертировать строку в число, но перевод не полон.

Существуют некоторые других распространенных предупреждений и ошибок в Perl. Например, Global symbol requires explicit package name и Use of uninitialized value.

Как избавиться от предупреждения?

Это приятно, что perl предупреждает вас (если попросить), когда перевод типов не полон, но нет ли функции вроде is_number, которая проверит, является ли данная строка числом?

Да и нет.

В Perl нет функции is_number, потому что это стало бы заявлением, будто бы программисты Perl знают, что является числом, а что нет. К сожалению, остальная часть мира не может прийти к окончательному соглашению по этому вопросу. Существуют системы, в которых строка ".2" признается числом, но в других системах она таковым не является. Еще более простой случай - "2.", как правило, не признается, но есть система, в которой это совершенно допустимое число.

Есть даже места, где 0xAB считается числом. Шестнадцатеричным.

Так что функции is_number не существует, но есть менее категоричные функции, такие как looks_like_number.

Это именно то, что вы думаете. Функция проверит, будет ли данная строка похожа на число для perl'а.

Она содержится в модуле Scalar::Util и ее используют следующим образом:

use strict;
use warnings;

use Scalar::Util qw(looks_like_number);

print "Сколько буханок хлеба мне купить? ";
my $loaves = <STDIN>;
chomp $loaves;

if (looks_like_number($loaves)) {
    print "Я пошел...\n";
} else {
    print "Извини, я не понял\n";
}

И не забудь молоко!