为什么File :: Slurp在返回列表时会返回标量?

时间:2010-06-02 13:43:48

标签: perl file-io perl-module perl-context

我是File :: Slurp模块的新手,在我第一次使用它时,它没有给出我期待的结果。我花了一段时间才弄明白,所以现在我对我为什么会看到这种行为感兴趣。

我对File :: Slurp的调用如下所示:

my @array = read_file( $file ) || die "Cannot read $file\n";

我包含了“die”部分,因为我习惯在打开文件时这样做。我的@array总是会在数组的第一个元素中得到文件的全部内容。最后我拿出了“|| die”部分,它按照我的预期开始工作。

这是一个例子来说明:

perl -de0

Loading DB routines from perl5db.pl version 1.22
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1):   0
DB<1> use File::Slurp

DB<2> $file = '/usr/java6_64/copyright'

DB<3> x @array1 = read_file( $file )
0  'Licensed material - Property of IBM.'
1  'IBM(R) SDK, Java(TM) Technology Edition, Version 6'
2  'IBM(R) Runtime Environment, Java(TM) Technology Edition, Version 6'
3  ''
4  'Copyright Sun Microsystems Inc, 1992, 2008. All rights reserved.'
5  'Copyright IBM Corporation, 1998, 2009. All rights reserved.'
6  ''
7  'The Apache Software License, Version 1.1 and Version 2.0'
8  'Copyright 1999-2007 The Apache Software Foundation. All rights reserved.'
9  ''
10  'Other copyright acknowledgements can be found in the Notices file.'
11  ''
12  'The Java technology is owned and exclusively licensed by Sun Microsystems Inc.'
13  'Java and all Java-based trademarks and logos are trademarks or registered'
14  'trademarks of Sun Microsystems Inc.  in the United States and other countries.'
15  ''
16  'US Govt Users Restricted Rights - Use duplication or disclosure'
17  'restricted by GSA ADP Schedule Contract with IBM Corp.'
DB<4> x @array2 = read_file( $file ) || die "Cannot read $file\n";

0  'Licensed material - Property of IBM.
IBM(R) SDK, Java(TM) Technology Edition, Version 6
IBM(R) Runtime Environment, Java(TM) Technology Edition, Version 6

Copyright Sun Microsystems Inc, 1992, 2008. All rights reserved.
Copyright IBM Corporation, 1998, 2009. All rights reserved.

The Apache Software License, Version 1.1 and Version 2.0
Copyright 1999-2007 The Apache Software Foundation. All rights reserved.

Other copyright acknowledgements can be found in the Notices file.

The Java technology is owned and exclusively licensed by Sun Microsystems Inc.
Java and all Java-based trademarks and logos are trademarks or registered
trademarks of Sun Microsystems Inc.  in the United States and other countries.

US Govt Users Restricted Rights - Use duplication or disclosure
restricted by GSA ADP Schedule Contract with IBM Corp.
'

为什么是||死有所作为?我有一种感觉,这可能更像是一个Perl优先级问题而不是File :: Slurp问题。我查看了File :: Slurp模块,如果出现问题,它看起来像是设置为croak,所以我想正确的方法是允许File :: Slurp为你呱呱叫。现在我只是好奇为什么我看到这些差异。

3 个答案:

答案 0 :(得分:9)

布尔运算符||比赋值运算符更紧密,并将函数调用放入标量上下文

my @array = read_file( $file ) || die "Cannot read $file\n";

这就是说:尝试读取文件,并返回文件的串联或die中的“return”作为@array中的第一个元素。你不会死,因为它读取文件并返回一个真值,尽管是一个标量值。

标准用法是语句或运算符(or),如下所示:

my @array = read_file( $file ) or die "Cannot read $file\n";

这会尝试在列表上下文中分配@array,然后在标量上下文中计算分配的列表,从而产生数组中的项目数。因此,首先分配数组,然后不要死,因为数组有条目。

第二种形式不会尝试将“die的”返回“分配给@array,因为分配是先完成的,所以@array要么保留文件的行,要么是空数组。

注意File::Slurp read_file的文档说:

  

列表上下文中,它将返回一个行列表(使用当前值$ /作为分隔符,包括对段落模式设置为''时的支持)。在标量上下文中,它将整个文件作为单个标量返回。 [ italics mine ]

并提供以下示例:

    my $text = read_file( 'filename' ) ;
    my @lines = read_file( 'filename' ) ;

但这些是最简单的情况,也是最基本的语境表达。分配给某种类型的变量并不能确保在列表上下文中分配@lines,而不管周围的代码如何。

答案 1 :(得分:6)

||运算符将其左侧操作数放在布尔(标量)上下文中:

  

C-style Logical Or

     

二进制||执行短路逻辑OR运算。也就是说,如果左操作数为true,则甚至不评估右操作数。标量或列表上下文如果被计算,则向下传播到右操作数。

你也可以凭经验发现:

#! /usr/bin/perl

sub lhs {
  my $ctx = wantarray;
  if (defined $ctx) {
    if ($ctx) { "list" }
    else      { "scalar" }
  }
  else { "void" }
}

print lhs || 0, "\n";

输出:

$ ./or-ctx.pl
scalar

要修复程序,可以稍微修改一下:

my @array = eval { read_file("/etc/issue") };
die unless @array;

仅当您要添加错误消息(存储在$@之后的特殊变量eval中)时才需要这样做,因为read_filedie {{1}}错。

答案 2 :(得分:4)

您的问题已经回答了。作为旁注,首先,请记住orand更适合流控制语句。但是,更重要的是,下面的检查

 my @array = read_file( $file ) || die "Cannot read $file\n";

完全没必要。默认情况下,File::Slurp::read_file croak出错:

  

err_mode

     

您可以使用此选项控制发生错误时read_file的行为方式。此选项默认为'croak'。你可以将它设置为'carp'或'quiet以便没有错误处理。