如果我写一个真正的参考\*STDOUT
而不是 typeglob like ,我会得到什么*STDOUT
?
4 回答
一个是typeglob,另一个是对它的引用。
据我所知,主要的实际区别是您不能将 typeglob 祝福到对象中,但您可以祝福 typeglob 引用(这就是这样IO::Handle
做的)
这种区别在“Perl Cookbook”的 7.16 节中有详细讨论。“将文件句柄存储在变量中”。
另一个区别是分配一个 glob 会为整个 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
*
表示一个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
您将获得对名为 的 typeglob 的引用STDOUT
。见perlref。
这就是它所说的:
使用反斜杠运算符无法创建对 IO 句柄(文件句柄或目录句柄)的真实引用。最多可以得到一个typeglob的引用,它实际上是一个完整的符号表条目。但是请参阅下面对 *foo{THING} 语法的解释。但是,您仍然可以像使用 IO 句柄一样使用类型 glob 和 globrefs。
perldata也很有帮助。
总之,这就像构建对文件句柄的引用。您可以将其用作一个。但是使用 typeglob,您也可以做其他事情。符号表包含所有名为 的变量的值STDOUT
,即$STDOUT
、@STDOUT
、%STDOUT
甚至&STDOUT
,以及文件句柄。您只需一个 typeglob 即可访问它们。但是如果STDOUT
您可能不必担心它,因为您%STDOUT
的代码中不太可能有 a 。
这种引用也是将文件句柄作为参数传递给函数的唯一方法。
sub myprint {
my $fh = shift;
print $fh "Hello World!\n";
}
&myprint(\*STDOUT);
Perl 提供了 3 种方法来获取相同的文件句柄:
*STDOUT
是一个类型球\*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
, not \*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 提供了一个临时值。当 sub 返回时,*FH
它失去了它的临时值,并FH
重新成为一个未打开的文件句柄。
解决方法是复制临时值。当 sub 返回时会发生这种情况*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
并且需要复制旧值,则必须使用 复制 typeglob *STDOUT
,而不是\*STDOUT
。您可能不需要复制该值。