2012-03-26 71 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 
}