Что означает "select ((select (s), $| = 1) [0])" делать в Perl?

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

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

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

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

Ответ 1

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

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

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

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

use IO::Handle;
$fh->autoflush;

Ответ 2

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

Первый бит:

( select(s), $|=1 )

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

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

( PREVIOUS_DEFAULT, 1 )[0]

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

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

 select( PREVIOUS_DEFAULT );

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

Ответ 3

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.

Ответ 4

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

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

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

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

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

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

Ответ 5

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

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

Ответ 7

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

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

является более читаемым.