\*STDOUT
のような型グロブではなく、実際の参照のようなものに書き込むと、何が得られ*STDOUT
ますか?
4 に答える
1 つはtypeglobで、もう 1 つはそれへの参照です。
私の知る限り、主な実際的な違いは、型グロブをオブジェクトに bless することはできませんが、型グロブ参照を bless することはできるということです(これがIO::Handle
行うことです) 。
この違いについては、「Perl クックブック」のレシピ 7.16 で詳しく説明しています。「ファイルハンドルを変数に格納する」.
もう 1 つの違いは、glob を割り当てると ENTIRE glob へのエイリアスが作成されるのに対し、glob 参照を割り当てると期待どおりに動作することです ( で説明したようにperldoc perlmod, "Symbol Tables" section
。説明するには:
@STDOUT=(5);
$globcopy1 = *STDOUT; # globcopy1 is aliased to the entire STDOUT glob,
# including alias to array @STDOUT
$globcopy2 = \*STDOUT; # globcopy2 merely stores a reference to a glob,
# and doesn't have anything to do with @STDOUT
print $globcopy1 "TEST print to globcopy1/STDOUT as filehandle\n";
print "TEST print of globcopy1/STDOUT as array: $globcopy1->[0]\n\n";
print $globcopy2 "TEST print to globcopy2/STDOUT as filehandle\n";
print "TEST print of globcopy2/STDOUT as array: $globcopy2->[0]\n\n";
プロデュース:
TEST print to globcopy1/STDOUT as filehandle
TEST print of globcopy1/STDOUT as array: 5
TEST print to globcopy2/STDOUT as filehandle
Not an ARRAY reference at line 8.
補足として、型グロブ参照がファイルハンドルを関数に渡す唯一の方法であるという噂は事実ではありません:
sub pfh { my $fh = $_[0]; print $fh $_[1]; }
pfh(*STDOUT, "t1\n");
pfh(\*STDOUT, "t2\n");
# Output:
# t1
# t2
*
は、シンボル テーブルのエントリである型グロブを示します。例えば:
my $x;
print *x;
が得られ*main::x
ます。
\
参照を示します。これを試して:
use YAML::XS;
print Dump *STDOUT;
print Dump \*STDOUT;
1 つ目はグロブ、2 つ目はリファレンスです。おそらくこれを行うとき:
my $fh = *STDOUT;
これはあまり意味がないと思いますが、実際にはグロブを新しいエントリにコピーしていclose STDOUT
ます$fh
. これ:
my $fh = \*STDOUT;
は単なる参照であり、それが優先されます。以下も参照してください。
http://perldoc.perl.org/perldata.html#Typeglobs-and-Filehandles
という名前の型グロブへの参照を取得しますSTDOUT
。perlrefを参照してください。
これについては次のように書かれています。
バックスラッシュ演算子を使用して IO ハンドル (ファイルハンドルまたはディレクトリハンドル) への真の参照を作成することはできません。取得できるのは、実際には完全なシンボル テーブル エントリである型グロブへの参照です。ただし、以下の *foo{THING} 構文の説明を参照してください。ただし、タイプ glob と globref を IO ハンドルのように使用することはできます。
perldataも役に立ちます。
結論として、ファイルハンドルへの参照を構築するようなものです。1枚でお使いいただけます。ただし、型グロブを使用すると、他のこともできます。STDOUT
シンボル テーブルには$STDOUT
、@STDOUT
、%STDOUT
、さらにはという名前のすべての変数の値と&STDOUT
、ファイル ハンドルが保持されます。1 つの型グロブだけでそれらすべてにアクセスできます。ただし、コードSTDOUT
に a が含まれていない可能性が高いため、おそらく心配する必要はありません。%STDOUT
この種の参照は、ファイルハンドルを引数として関数に渡す唯一の方法でもあります。
sub myprint {
my $fh = shift;
print $fh "Hello World!\n";
}
&myprint(\*STDOUT);
Perl は、同じファイルハンドルを取得する 3 つの方法を提供します:
*STDOUT
型グロブです\*STDOUT
型グロブへの参照です*STDOUT{IO}
undef または IO::Handle への参照のいずれかです
私は今\*STDOUT
、一貫性のために使用することを好みます。ファイルハンドルを自動有効化するために使用open(my $handle, ...)
すると、Perl は型グロブへの参照を与えてくれます。したがって、どちらかまたは開いているファイルを使用したい場合はSTDOUT
、次のように書くかもしれません
my $handle;
if ($path eq "-") {
$handle = \*STDOUT;
} else {
open($handle, '>', $path) or die "Can't open $path: $!";
}
したがって、私のハンドルは常に型グロブへの参照です。この一貫性はあまり重要ではありません。私のコードの残りの部分は、型グロブまたは他の種類のファイルハンドルへの参照があるかどうかを気にする必要はありません。
の好みを考えると、機能するが失敗\*FH
する例を見つけて驚いています。perlsub の "Pass by Reference"で、次の例を見つけました。*FH
\*FH
新しいファイルハンドルを生成することを計画している場合は、これを行うことができます。その参照ではなく、生の *FH だけを返すことに注意してください。
sub openit { my $path = shift; local *FH; return open (FH, $path) ? *FH : undef; }
perlsub は理由を説明していませんが、実際*FH
には ではなくを返す必要があります。\*FH
スクリプトでサブを呼び出して、自分で確認しました。
use strict;
use warnings;
sub openit {
my $path = shift;
local *FH;
return open (FH, $path) ? *FH : undef;
}
my $it = openit '</etc/fstab' or die "Can't open it: $!";
if (defined($_ = <$it>)) {
print "Its first line is $_";
} else {
print "It has no first line\n";
}
戻り値が の*FH
場合、スクリプトは機能します。に変更すると\*FH
、スクリプトが失敗します。警告を使用しているため、次のように表示されます。
readline() on unopened filehandle FH at scratch.pl line 11.
It has no first line
これは\*FH
、グローバル変数を指しているために発生しました。サブでlocal *FH
は、一時的な値をグローバル型グロブに与えました。サブルーチンが戻ると、*FH
その一時的な値が失わFH
れ、開かれていないファイルハンドルに戻りました。
修正は、一時的な値をコピーすることです。これは、サブが戻ったときに発生します*FH
。左辺値サブルーチンではないため、型グロブをコピーします。*FH
これで、sub がではなくを返さなければならない理由がわかりました\*FH
。
サブルーチンが参照を返すようにしたい場合は、型グロブをコピーしてから参照を取得できます。
local *FH;
return open (FH, $path) ? \(my $glob = *FH) : undef;
または、参照を自動有効化できます。
my $globref;
return open ($globref, $path) ? $globref : undef;
の値を変更しSTDOUT
、古い値をコピーする必要がある場合は、型グロブを*STDOUT
ではなくでコピーする必要があります\*STDOUT
。おそらく、値をコピーする必要はありません。