Perl で書かれた恐ろしいコードを見たことがありますが、このコードの頭も尻尾もわかりません。
select((select(s),$|=1)[0])
これは、サーバーとの通信に使用するネットワーク コードにあり、バッファリングと関係があると思います (設定されているため$|
)。
select
しかし、複数の呼び出しや配列参照がある理由がわかりません。誰でも私を助けることができますか?
これは、STDOUT 以外のファイルハンドルに autoflush を設定するための厄介な小さなイディオムです。
select()
提供されたファイルハンドルを取り、(基本的に) STDOUT をそれで置き換え、完了すると古いファイルハンドルを返します。
(select($s),$|=1)
そのため、ファイルハンドルをリダイレクトし (select
古いものを返すことに注意してください)、autoflush ( ) を設定します$| = 1
。リスト ( (...)[0]
) でこれを行い、最初の値 (select
呼び出しの結果である元の STDOUT) を返し、それを別の値select
に戻して元の STDOUT ファイルハンドルを復元します。ふぅ。
しかし、これで理解できました (まあ、多分 ;))、代わりに次のようにします。
use IO::Handle;
$fh->autoflush;
コードを理解する方法は、コードを分解することです。括弧内のものは外側のものの前に起こることを知っています。これは、他の言語でコードが何をしているかを理解するのと同じ方法です。
最初のビットは次のとおりです。
( select(s), $|=1 )
このリストには 2 つの操作の結果である 2 つの要素があります。1s
つはデフォルトとしてファイルハンドルを選択し、もう 1 つ$|
は true 値に設定します。これ$|
は、現在選択されているファイルハンドルにのみ適用されるファイルハンドルごとの変数の 1 つです (「効果的な Perlerでグローバル変数を理解する」を参照してください)。最後に、前のデフォルトのファイルハンドル ( の結果) と 1の 2 つの項目のリストがあります。select
次の部分は、インデックス 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
してください。
perldoc -f selectを確認してください。の意味については、 perldoc perlvar$|
を参照してください。
IO::Handle の読み込みをスキップするのは最適化のしすぎです。
use IO::Handle;
$fh->autoflush(1);
はるかに読みやすいです。