4

如果我写一个真正的参考\*STDOUT而不是 typeglob like ,我会得到什么*STDOUT

4

4 回答 4

8

一个是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
于 2012-05-07T07:10:38.933 回答
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

于 2012-05-07T07:06:17.223 回答
3

您将获得对名为 的 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);
于 2012-05-07T07:03:19.233 回答
1

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。您可能不需要复制该值。

于 2016-04-18T01:58:00.273 回答