如果我写一个真实的引用,例如\*STDOUT
而不是类似*STDOUT
的类型,我会获得什么?
答案 0 :(得分:8)
一个是typeglob,另一个是对它的引用。
据我所知,主要的实际区别在于你不能将typeglob加入对象,但你可以祝福typeglob引用(这是IO::Handle
所做的)
这一区别在“Perl Cookbook”,Recipe 7.16中有详细讨论。 “将文件句柄存储在变量中”。
另一个不同之处在于,分配一个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.
作为旁注,传闻说typeglob引用是将文件句柄传递给函数的唯一方法不是这样:
sub pfh { my $fh = $_[0]; print $fh $_[1]; }
pfh(*STDOUT, "t1\n");
pfh(\*STDOUT, "t2\n");
# Output:
# t1
# t2
答案 1 :(得分:4)
*
表示一个typeglob,它是符号表中的一个条目。例如:
my $x;
print *x;
将产生*main::x
。
\
表示参考。试试这个:
use YAML::XS;
print Dump *STDOUT;
print Dump \*STDOUT;
第一个是glob,第二个是参考。大概是你这样做的时候:
my $fh = *STDOUT;
您实际上是将glob复制到一个新条目中,虽然我认为这不是很有意义 - 如果您现在close STDOUT
,$fh
也会关闭。这样:
my $fh = \*STDOUT;
只是一个参考,这是首选。另见:
http://perldoc.perl.org/perldata.html#Typeglobs-and-Filehandles
答案 2 :(得分:3)
您将获得对名为STDOUT
的typeglob的引用。请参阅perlref。
以下是对此的说法:
无法创建对IO句柄的真实引用 (filehandle或dirhandle)使用反斜杠运算符。你最 can get是对typeglob的引用,实际上是一个完整的 符号表条目。但请参阅* foo {THING}语法的解释 下面。但是,您仍然可以使用类型globs和globrefs 他们是IO句柄。
perldata也很有用。
总之,它就像构建对文件句柄的引用。您可以将其作为一个使用。但是使用typeglob,你也可以做其他事情。符号表包含名为STDOUT
的所有变量的值,即$STDOUT
,@STDOUT
,%STDOUT
甚至&STDOUT
,以及文件句柄。只需一个typeglob就可以访问它们。但是如果是STDOUT
,您可能不必担心,因为您的代码中可能不会有%STDOUT
。
这种引用也是将文件句柄作为参数传递给函数的唯一方法。
sub myprint {
my $fh = shift;
print $fh "Hello World!\n";
}
&myprint(\*STDOUT);
答案 3 :(得分:1)
Perl提供了3种获取相同文件句柄的方法:
*STDOUT
是typeglob \*STDOUT
是对typeglob的引用*STDOUT{IO}
是undef或对IO :: Handle的引用我现在更喜欢使用\*STDOUT
来保持一致性。当我使用open(my $handle, ...)
自动生成文件句柄时,Perl给我一个typeglob的引用。因此,如果我想使用STDOUT
或打开文件,我可能会写
my $handle;
if ($path eq "-") {
$handle = \*STDOUT;
} else {
open($handle, '>', $path) or die "Can't open $path: $!";
}
所以我的句柄始终是对typeglob的引用。这种一致性并不太重要。我的其余代码不应该关心它是否引用了typeglob或其他类型的文件句柄。
鉴于我对\*FH
的偏好,我很惊讶地发现*FH
有效但\*FH
失败的示例。在perlsub, "Pass by Reference"中,我找到了这个例子:
如果您计划生成新的文件句柄,则可以执行此操作。注意只传回裸* FH,而不是它的参考。
sub openit { my $path = shift; local *FH; return open (FH, $path) ? *FH : undef; }
它确实需要传回*FH
,而不是\*FH
,尽管perlsub没有解释原因。我通过在脚本中调用sub来验证它自己:
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
指向全局变量。在sub中,local *FH
为全局typeglob提供了临时值。返回时,*FH
丢失了临时值,FH
又恢复为未打开的文件句柄。
修复方法是复制临时值。当子返回*FH
时会发生这种情况。它复制了typeglob,因为它不是左值子。现在我知道为什么sub必须返回*FH
,而不是\*FH
。
如果我想让sub返回引用,我可以复制typeglob然后参考:
local *FH;
return open (FH, $path) ? \(my $glob = *FH) : undef;
或者我可以自动生成参考:
my $globref;
return open ($globref, $path) ? $globref : undef;
如果更改STDOUT
的值并且需要复制旧值,则必须使用*STDOUT
复制typeglob,而不是\*STDOUT
。您可能不需要复制该值。