Что выбирает ((выберите (ы), $ | = 1) [0]) & # 8221; делать в Perl?
Вопрос
Я видел какой-то ужасающий код, написанный на Perl, но я не могу понять, как это сделать:
select((select(s),$|=1)[0])
Это некоторый сетевой код, который мы используем для связи с сервером, и я предполагаю, что это как-то связано с буферизацией (поскольку она устанавливает $ |
).
Но я не могу понять, почему существует несколько вызовов select
или ссылка на массив. Кто-нибудь может мне помочь?
Решение
Это небольшая неприятная идиома для установки автозаполнения для файлового дескриптора, отличного от STDOUT. Р>
select ()
берет предоставленный файловый дескриптор и (в основном) заменяет им STDOUT и возвращает старый файловый дескриптор, когда это сделано. Р>
Итак, (select ($ s), $ | = 1)
перенаправляет дескриптор файла (помните, select
возвращает старый) и устанавливает автозапуск ( $ | = 1
). Он делает это в списке ( (...) [0]
) и возвращает первое значение (которое является результатом вызова select
- исходный STDOUT), а затем передает это обратно в другой select
, чтобы восстановить исходный дескриптор файла STDOUT. Уф.
Но теперь вы понимаете это (ну, может быть;)), сделайте это вместо этого:
use IO::Handle;
$fh->autoflush;
Другие советы
Способ выяснить любой код - это выделить его. Вы знаете, что вещи внутри скобок происходят раньше, чем вещи снаружи. Это так же, как вы выясните, что код делает на других языках.
Тогда первый бит:
( select(s), $|=1 )
Этот список содержит два элемента, которые являются результатом двух операций: один для выбора дескриптора файла s
в качестве значения по умолчанию, а второй - для установки для $ |
истинного значения. , $ |
- это одна из переменных для каждого дескриптора файла, которая применяется только к текущему выбранному дескриптору файла (см. Понимать глобальные переменные в Эффективном Perler ). В итоге у вас есть список из двух элементов: предыдущий дескриптор файла по умолчанию (результат select
) и 1.
Следующая часть - это буквальный фрагмент списка для извлечения элемента с индексом 0:
( PREVIOUS_DEFAULT, 1 )[0]
Результатом этого является один элемент, который является предыдущим дескриптором файла по умолчанию.
Следующая часть берет результат среза и использует его в качестве аргумента для другого вызова select
select( PREVIOUS_DEFAULT );
Итак, по сути, вы установили $ |
для файлового дескриптора и в итоге вернулись к тому, с чего начали с файловым дескриптором по умолчанию.
select($fh)
Выберите новый дескриптор файла по умолчанию. См. http://perldoc.perl.org/functions/select.html
(select($fh), $|=1)
Включите автозапуск. См. http://perldoc.perl.org/perlvar.html
(select($fh), $|=1)[0]
Возвращает первое значение этого кортежа.
select((select($fh), $|=1)[0])
выберите
, то есть восстановите старый дескриптор файла по умолчанию.
Эквивалент
$oldfh = select($fh);
$| = 1;
select($oldfh);
что означает
use IO::Handle;
$fh->autoflush(1);
как показано на странице perldoc.
В другом месте я однажды предложил, чтобы более понятная версия была такой:
for ( select $fh ) { $| = 1; select В другом месте я однажды предложил, чтобы более понятная версия была такой:
for my $prevfh ( select $fh ) { $| = 1; select $prevfh }
Это сохраняет единственное преимущество компактной идиомы, заключающееся в том, что в окружающей области не нужно объявлять переменные.
Или, если вам не нравится $ _
, вы можете написать это так:
<*>
Область действия $ prevfh
ограничена блоком for
. (Но если вы напишите на Perl, у вас действительно не будет повода быть осторожным в отношении $ _
.)
}
Это сохраняет единственное преимущество компактной идиомы, заключающееся в том, что в окружающей области не нужно объявлять переменные.
Или, если вам не нравится $ _
, вы можете написать это так:
Область действия $ prevfh
ограничена блоком for
. (Но если вы напишите на Perl, у вас действительно не будет повода быть осторожным в отношении $ _
.)
Это слишком умный код для включения очистки буфера на дескрипторе s
и повторного выбора текущего дескриптора.
Подробнее см. perldoc -f select
.
пожалуйста, проверьте perldoc -f select . Значение $ |
см. В разделе perldoc perlvar
Это чрезмерная оптимизация, чтобы пропустить загрузку IO :: Handle.
use IO::Handle;
$fh->autoflush(1);
гораздо удобнее для чтения.