Чтение данных из стандартного ввода

Получить данные из стандартного потока ввода несложно. Мы уже делали это при помощи оператора .1 Выполнение этого оператора в скалярном контексте дает следующую строку входных данных:

$line = ; # Прочитать следующую строку
chomp($line); # Удалить завершитель
chomp($line = ); # То же самое, но более идиоматично

При достижении конца файла оператор построчного ввода возвращает undef; это обстоятельство часто используется для выхода из цикла:

while (defined($line = )) {
print "I saw $line";
}

В первой строке происходит много всего: мы читаем входные данные в переменную, проверяем ее на определенность, и если она определена (то есть если цикл еще не достиг конца входных данных), выполняется тело цикла while. Таким образом, в теле цикла переменная $line1 по очереди содержит каждую строку цикла. Подобная операция выполняется очень часто; вполне естественно, что в Perl для нее была создана сокращенная форма записи, которая выглядит так:

while () {
print "I saw $_";
}

Под это сокращение Ларри задействовал заведомо бесполезную синтаксическую конструкцию.


Буквально здесь говорится следующее: «Прочитать строку входных данных и проверить ее на истинность (обычно условие выполняется). Если строка истинна, войти в цикл while и отбросить прочитанную строку!» Ларри знал, что это бесполезная операция; никому не придет в голову выполнять ее в реальной программе Perl. Ларри взял этот бесполезный синтаксис и сделал его полезным. По сути эта конструкция означает, что Perl должен сделать то, что мы видели в более раннем цикле: прочитать входные данные в переменную и (при условии, что результат определен, то есть мы не достигли конца файла) войти в цикл while. Но вместо того чтобы сохранять результат в $line, Perl использует переменную по умолчанию $_, как если бы запись выглядела так:

while (defined($_ = )) {
print "I saw $_";
}

Прежде чем двигаться дальше, вы должны предельно четко понять: это сокращение работает только в такой записи. Если оператор построчного ввода находится в другом месте (например, в отдельной команде), строка не будет прочитана в переменную $_ по умолчанию. Сокращение работает только тогда, когда условие цикла while2 не содержит ничего, кроме оператора построчного ввода.


Если в условии появится что-нибудь еще, сокращение работать не будет. В остальном оператор построчного ввода () никак не связан с «главной» переменной по умолчанию Perl $_. Но именно в данном конкретном случае ввод сохраняется в этой переменной.

С другой стороны, при выполнении оператора построчного ввода в списочном контексте вы получаете все (оставшиеся) строки ввода в виде списка – каждый элемент соответствует одной строке:

foreach () {
print "I saw $_";
}

Еще раз подчеркнем: оператор построчного ввода никак не связан с «главной» переменной по умолчанию. Но в данном случае в цикле foreach по умолчанию используется управляющая переменная $_. Таким образом, в этом цикле в переменную $_ последовательно заносятся все строки входных данных. Звучит знакомо и не без оснований: это же поведение мы встречали в цикле while. Разве не так? Различия скрыты внутри. В цикле while Perl читает строку входных данных, помещает ее в переменную и выполняет тело цикла, после чего возвращается за следующей строкой ввода. Но в цикле foreach оператор построчного ввода используется в списочном контексте (так как для выполнения цикла foreach необходим список). Таким образом, перед началом выполнения должны быть прочитаны все входные данные. Попробуйте прочитать 400Qмегабайтный журнал веб-сервера и вы мгновенно поймете эти различия! Обычно подобный код рекомендуется использовать в сокращенной записи с циклом while, чтобы входные данные обрабатывались по строкам (если это возможно).

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Perl на эту тему:
Аргументы вызова
Ввод данных оператором <>
Вывод функцией say
Закрытие файлового дескриптора
Запись данных в стандартный вывод

Вернуться в раздел: Perl / 4. Ввод и вывод