2012-03-26 72 views
3

是否有可能在某种程度上指示Perl中的数组是否未定义或为空?我发现自己遇到了一些情况,希望能够区分一个空数组和尚未填充的数组(或因某种原因填充失败)。Perl中的未定义数组

因此,例如,用一个数组引用我可以这样做:

my $apples; 
$apples = get_apples(); 
if(defined $apples){ 

if(scalar @$apples == 0){ 
# We successfully got the list of apples, but there were none 
} 

}else{ 

# There was a problem getting the list of apples 

} 

我这个唯一的抱怨是“我的$苹果”不告诉你,$苹果打算为一个数组参考,所以@apples会更具体。

它没有看到有一种方法可以显式地对数组做某事,是这样吗?总是需要另一个变量来指示数组是否被成功填充?

my @apples; 
(@apples) = get_apples(); 

永远不能测试苹果的成功返回,对吗?或者我缺少一些整洁的东西?

编辑︰ 我知道,get_apples可以返回一个成功和一个列表来填充数组,但我很好奇,如果有一种方法来指示一个空值或未定义的值只有一个数组。

+0

我不知道这是你在问什么,但Perl的认为空数组成为失败值。 – Neil 2012-03-26 23:03:05

+1

@ Neil“假”不是“失败”的同义词。 – Schwern 2012-03-26 23:09:28

+1

我区分有人告诉我“没有符合条件的结果”和“500内部服务器错误”:P – GoldenNewby 2012-03-26 23:14:21

回答

7

在Perl中,空数组和未初始化数组之间没有区别。

$ perl -MDevel::Peek -e 'print Dump(\@a)' 
SV = RV(0x20033b00) at 0x20033af0 
    REFCNT = 1 
    FLAGS = (TEMP,ROK) 
    RV = 0x20091830 
    SV = PVAV(0x200350c0) at 0x20091830 
    REFCNT = 2 
    FLAGS =() 
    ARRAY = 0x0 
    FILL = -1 
    MAX = -1 
    ARYLEN = 0x0 
    FLAGS = (REAL) 

$ perl -MDevel::Peek -e '@a=(); print Dump(\@a)' 
SV = RV(0x20033b00) at 0x20033af0 
    REFCNT = 1 
    FLAGS = (TEMP,ROK) 
    RV = 0x20091818 
    SV = PVAV(0x200350c0) at 0x20091818 
    REFCNT = 2 
    FLAGS =() 
    ARRAY = 0x0 
    FILL = -1 
    MAX = -1 
    ARYLEN = 0x0 
    FLAGS = (REAL) 

你唯一的希望可能是检查内部AV对象的MAX属性,看看是否使用了数组包含任何数据:

use B; 
@b =(); 
@c = (1..100); @c =(); 
print B::svref_2object(\@b)->MAX;  # -1 
print B::svref_2object(\@c)->MAX;  # 99 
+0

我爱你的答案,但我讨厌现在我会开始偷看东西。 – GoldenNewby 2012-03-26 23:15:12

+0

Subs不能返回数组,那么你检查的这个'@ a'是什么? – ikegami 2012-03-27 00:34:08

+0

@ikegami如果这是一个列表与数组的事情,那是无益的钝和迂腐。清楚的解释或保持独立。 – Schwern 2012-03-28 01:31:11

0

你之所以能做到my $apples;,填充@$applesget_apples()子程序中,后来做if(@$apples==0)是因为标量为autovivification

由于暴徒指出,这不适用于阵列。

解决的办法可能是有get_apples()通过散列引用(或者,如果你想更Enterprisey,一个GetAppleReturn对象),在伪代码,看起来像

{ 
    success=>1,# or 0 if it failed 
    apples=>[$apple1,$apple2,...] #array reference of apples 
} 

,那么你可以这样做:

my @apples; 
my $rv=get_apples(); 
if($rv->{success}) 
{ 
    if(scalar(@{$rv->{apples}})==0) 
    { 
    print "Success, but no apples.\n"; 
    } 
    else 
    { 
    #do whatever 
    } 
} 
else 
{ 
    print "There was a problem getting the apples. How do ya like them apples?\n"; 
} 
6
  • 是否有可能以某种方式表明,如果Perl中的数组是未定义或为空?

编号数组只能是空的或包含标量。

有一个更好的方法来做你想做的:抛出一个异常。分离错误代码和返回值自从C开始就是一个bug。它使得函数变得复杂,并导致更多的错误。例外情况可以方便地解决这个问题,而且您不必通过错误检查(或者更可能忘记)来哄骗代码。

sub get_apples { 
    ... 
    die "How do you like them apples?" if $it_didnt_work; 
    return @apples; 
} 

# If get_apples() fails, the program throws an error. Good, that 
# should be the default behavior. 
my @apples = get_apples(); 

# Or maybe you want to do something with the error. 
my @apples = eval { get_apples() }; 
if([email protected]) { 
    ...handle the error... 
} 
+2

+1,但这些还不是C的日子吗? – GoldenNewby 2012-03-26 23:16:56

+0

这很好地展示了如何在perl中使用异常:http://c2.com/cgi/wiki?ExceptionHandlingInPerl – slm 2013-09-04 01:54:16

0

如何使用ref()

my $apples; 

print 'what type of object is $apples? ' . ref($apples) . $/; 

$apples = get_apples(); 

print 'what type of object is $apples now? ' . ref($apples) . $/; 

sub get_apples { 
    my $empty_apple_array = []; 
    return $empty_apple_array; 
} 

当$苹果首次创建ref()回报什么,因为它不是任何一个参考呢。

然后我们把它作为一个空数组的引用。现在ref()知道它是一个数组引用,即使它是空的。

+0

是的,但问题不在于如何使用引用来处理这个问题,它是如何处理的与一个数组。 – GoldenNewby 2012-03-27 03:10:11

-1

即使Perl可以区分未初始化的数组和空数组(它不能),它也不会帮助您确定get_apples是否返回了错误,因为您无法使my @apples = get_apples()不做任务当发生错误时。

你可能会错误地认为return @a返回一个数组。 Subs不能返回数组。他们只能返回0个或更多标量。 return @a返回@a的结果,它是列表上下文中数组的内容。

无法通过返回的值区分因零错误而返回的零元素与零元素的成功响应。 (你可以使用了带外的通道,如课程的异常或全局变量。)

因为潜艇只能返回标量的列表,只有两件事情可以做:

  • 计算返回的标量数。
  • 检查返回的标量。

为了实现您的目标,您需要找到一种情况,其中一种情况因错误和成功而异。

当返回数组ref时,检查返回的值是否被定义。

如果成功返回的第一个值(如果有的话)总是被定义的,你可以做类似的事情,但这很丑陋。

sub apples { 
    if (...error...) { 
     return undef; 
    } else { 
     return ...; 
    } 
} 

my @apples = apples(); 
if (@apples && !defined($apples[0])) { 
    ... an error occurred... 
} 

我推荐反对。

0

你可以返回一个包含民主基金的价值表示这是一个错误的单元素数组,然后测试这样的:

my @apples = get_apples(); 
if (@apples) { 
    if (defined $apples[0]) { 
     # you have apples 
    } else { 
     # some error occurred 
    } 
} else { 
    # no apples 
}