Что "select ((select (s), $ | = 1) [0])" делает в Perl? - PullRequest
30 голосов
/ 13 октября 2008

Я видел какой-то ужасающий код, написанный на Perl, но я не могу понять, как это сделать:

select((select(s),$|=1)[0])

Это некоторый сетевой код, который мы используем для связи с сервером, и я предполагаю, что это как-то связано с буферизацией (поскольку она устанавливает $|).

Но я не могу понять, почему существует несколько вызовов select или ссылка на массив. Кто-нибудь может мне помочь?

Ответы [ 7 ]

63 голосов
/ 13 октября 2008

Это неприятная маленькая идиома для установки автозаполнения на файловом дескрипторе, отличном от STDOUT.

select() берет предоставленный файловый дескриптор и (в основном) заменяет STDOUT этим, и он возвращает старый файловый дескриптор, когда это сделано.

То есть (select($s),$|=1) перенаправляет дескриптор файла (помните, select возвращает старый) и устанавливает автозапуск ($| = 1). Он делает это в списке ((...)[0]) и возвращает первое значение (которое является результатом вызова select - исходного STDOUT), а затем передает , который , обратно в другой select для восстановить исходный дескриптор файла STDOUT. Уф.

Но теперь вы понимаете это (ну, может быть;)), сделайте это вместо этого:

use IO::Handle;
$fh->autoflush;
29 голосов
/ 13 октября 2008

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

Первый бит:

( select(s), $|=1 )

Этот список состоит из двух элементов, которые являются результатом двух операций: один для выбора дескриптора файла s по умолчанию, а другой - для установки $| в истинное значение. $| - это одна из переменных для каждого дескриптора файла, которая применяется только к текущему выбранному дескриптору файла (см. Понимание глобальных переменных в Effective Perler ). В итоге у вас есть список из двух элементов: предыдущий дескриптор файла по умолчанию (результат select) и 1.

Следующая часть - это буквальный фрагмент списка для извлечения элемента в индексе 0:

( PREVIOUS_DEFAULT, 1 )[0]

Результатом этого является один элемент, который является предыдущим дескриптором файла по умолчанию.

Следующая часть берет результат среза и использует его в качестве аргумента для другого вызова select

 select( PREVIOUS_DEFAULT );

Таким образом, по сути, вы установили $| для файлового дескриптора и в итоге вернулись к тому, с чего начали с файловым дескриптором по умолчанию.

20 голосов
/ 18 февраля 2010
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.

10 голосов
/ 14 октября 2008

В другом месте я однажды предложил, чтобы более понятная версия была такой:

for ( select $fh ) { $| = 1; select $_ }

Это сохраняет единственное преимущество компактной идиомы, заключающееся в том, что в окружающей области не нужно объявлять переменные.

Или, если вам не нравится $_, вы можете написать это так:

for my $prevfh ( select $fh ) { $| = 1; select $prevfh }

Область действия $prevfh ограничена блоком for. (Но если вы напишите на Perl, у вас действительно не будет повода быть пугливым по поводу $_.)

8 голосов
/ 13 октября 2008

Это слишком умный код для включения очистки буфера на дескрипторе s и последующего повторного выбора текущего дескриптора.

Подробнее см. perldoc -f select.

2 голосов
/ 18 февраля 2010

Это чрезмерная оптимизация, чтобы пропустить загрузку IO :: Handle.

use IO::Handle;
$fh->autoflush(1);

гораздо удобнее для чтения.

2 голосов
/ 18 февраля 2010

, пожалуйста, отметьте perldoc -f выберите . Для значения $|, пожалуйста, проверьте perldoc perlvar

...