Что "select((select(s),$|=1)[0])" делает в Perl?
Я видел какой-то ужасающий код, написанный на Perl, но я не могу понять, как это сделать:
select((select(s),$|=1)[0])
Это в каком-то сетевом коде, который мы используем для связи с сервером, и я предполагаю, что это как-то связано с буферизацией (так как она устанавливает $|
).
Но я не могу понять, почему есть несколько select
вызовы или ссылка на массив. Может кто-нибудь мне помочь?
7 ответов
Это неприятная маленькая идиома для установки автозаполнения на файловом дескрипторе, отличном от STDOUT.
select()
берет предоставленный файловый дескриптор и (в основном) заменяет STDOUT этим, и он возвращает старый файловый дескриптор, когда это сделано.
Так (select($s),$|=1)
перенаправляет файловый дескриптор (помните select
возвращает старую) и устанавливает автозапуск ($| = 1
). Это делает это в списке ((...)[0]
) и возвращает первое значение (которое является результатом select
вызов - исходный STDOUT), а затем передает это обратно в другой select
восстановить исходный дескриптор файла STDOUT. Уф.
Но теперь вы понимаете это (ну, может быть;)), сделайте это вместо этого:
use IO::Handle;
$fh->autoflush;
Способ выяснить любой код состоит в том, чтобы выделить его. Вы знаете, что вещи в скобках происходят раньше, чем вещи снаружи. Это так же, как вы выясните, что делает код на других языках.
Первый бит тогда:
( select(s), $|=1 )
Этот список содержит два элемента, которые являются результатом двух операций: один для выбора s
дескриптор файла по умолчанию, а затем установить $|
к истинному значению. $|
является одной из переменных дескриптора файла, которые применяются только к текущему выбранному дескриптору файла (см. Общие сведения о глобальных переменных в The Effective 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])
select
это, то есть восстановить старый дескриптор файла по умолчанию.
Эквивалентно
$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, у вас действительно не будет повода быть пугливым $_
.)
Это слишком умный код для включения очистки буфера на дескрипторе s
и затем повторно выбирая текущий дескриптор.
Увидеть perldoc -f select
для большего.
Это чрезмерная оптимизация, чтобы пропустить загрузку IO::Handle.
use IO::Handle;
$fh->autoflush(1);
гораздо более читабельным.
Пожалуйста, проверьте perldoc -f выберите. Для смысла $|
Пожалуйста, проверьте Perldoc Perlvar