2010-11-10 128 views
2

我有一個Perl腳本,其中變量必須在腳本可以繼續執行之前被初始化。冗長的if聲明,我檢查每個變量是明顯的選擇。但也許有一種更優雅或簡潔的方式來檢查幾個變量。如何在Perl中檢查幾個變量是否爲空

編輯: 我不需要檢查「定義」,他們總是定義一個空字符串,我需要檢查所有非空。

例子:

my ($a, $b, $c) = ("", "", ""); 

# If-clauses for setting the variables here 

if(!$a || !$b || !$c) { 
    print "Init failed\n"; 
} 
+0

如果您提供了一個當前如何操作的示例,那麼您可能會得到更多/更好的答案,包括在一個或多個尚未初始化時的適當反應。 (拋出一個錯誤?將它們設置爲默認值?等等) – 2010-11-10 09:30:10

回答

8

我假設意味着空字符串,不只是任何虛假的價值。也就是說,如果0"0"是永遠有效的值初始化後,目前公認的答案會給你錯誤的結果:

use strict; use warnings; 

my ($x, $y, $z) = ('0') x 3; 
# my ($x, $y, $z) = ('') x 3; 

for my $var ($x, $y, $z) { 
    die "Not properly initialized\n" unless defined($var) and length $var; 
} 

現在,這是一個驗證漂亮沒用,因爲,很可能更多,你如果出現這種情況,想知道哪個變量沒有正確初始化。

通過將您的配置參數保存在散列中可以更好地提供服務,以便您輕鬆檢查哪些已正確初始化。

use strict; use warnings; 

my %params = (
    x => 0, 
    y => '', 
    z => undef, 
); 

while (my ($k, $v) = each %params) { 
    validate_nonempty($v) 
     or die "'$k' was not properly initialized\n"; 
} 

sub validate_nonempty { 
    my ($v) = @_; 
    defined($v) and length $v; 
} 

或者,如果要列出所有不正確初始化是:

my @invalid = grep is_not_initialized($params{$_}), keys %params; 
die "Not properly initialized: @invalid\n" if @invalid; 

sub is_not_initialized { 
    my ($v) = @_; 
    not (defined($v) and length $v); 
} 
+0

+1爲params散列並捕獲包括OP在內的所有人都將「0」視爲未初始化的錯誤 – DVK 2010-11-10 15:56:28

+0

在您的中間代碼片段中,我沒有看到使用的是「validate_nonempty」子集。它需要在那裏嗎? – Matt 2016-11-29 15:47:10

+0

@Matt謝謝你的注意。是的,它確實需要在那裏......我一定在意外地刪除了一些東西的同時擺弄這個帖子。 – 2016-11-29 16:30:28

8

你所說的 「初始化」 是什麼意思?具有不是「undef」的值?

對於少量值,直截了當,如果檢查是恕我直言,最易讀/可維護。

if (!$var1 || !$var2 || !$var3) { 
    print "ERROR: Some are not defined!"; 
} 

順便說一句,檢查!$var是在「0」的可能的錯誤是在Perl假,因此初始化爲「0」將失敗該檢查的字符串。這是一個很大更好地使用$var eq ""

或者更好的是,空間的東西出來> 3倍的值

if (!$var1   # Use this if your values are guarantee not to be "0" 
    || $var2 eq ""  # This is a LOT better since !$var fails on "0" value 
    || $var3 eq "") { 

    print "ERROR: Some are not defined!"; 
} 

如果有這麼多的值,檢查上面變得難以閱讀(儘管每行檢查在第二個例子中,它並沒有真正發生過),或者如果值存儲在陣列,您可以使用grep抽象掉了檢查:

# We use "length" check instead of "$_ eq ''" as per tchrist's comment below 
if (grep { length } ($var1, $var2, $var3, $var4, $var5, @more_args)) { 
    print "ERROR: Some are not defined!"; 
} 

如果你必須知道哪些的價值觀a再沒有定義,你可以使用循環(留給讀者一個明顯的鍛鍊; Tibial),或地圖招:

my $i = -1; # we will be pre-incrementing 
if (my @undefined_indexes = map { $i++; $_ ?() : $i } 
           ($var1, $var2, $var3, $var4, $var5, @more_args)) { 

    print "ERROR: Value # $_ not defined!\n" foreach @undefined_indexes; 
} 
+3

我認爲,如果您發現自己明確編寫'$ _',那麼您可能在Perl中做得不是最理想的。我特別討厭'$ _ =〜/ foo /'。我經常寫'grep {length} @ list','map {hex} @ list'或'for(@list){s/foo/bar /}'。即使'鍵%h == grep {defined $ h {$ _}}鍵%h'也可以是'values%h == grep {defined} values%h'。閉包表達式足夠短,可以在'grep','map','first','all',&c的頭部保存'$ _'的含義。對'$ this'和'$ that'進行混合訪問的較長代碼值得把名稱放到抽象中:'$ _'實際上並不適用於此。 – tchrist 2010-11-10 15:26:02

+0

@tchrist - 好點。鑑於用戶澄清他正在檢查''「'而不是'undef','length'是一個不錯的選擇 - 編輯。如何在不使用'$ _'的情況下襬脫'undef'? – DVK 2010-11-10 15:49:00

+0

'@list == grep {defined} @ list'來確定它們是否都是,或'@list = grep {defined} @ list'來清除那些不是。 – tchrist 2010-11-10 15:53:11

7
use List::Util 'first'; 

if (defined first { $_ ne "" } $a, $b, $c) { 
    warn "empty"; 
}  
+0

它看起來很奇怪,但它起作用,並且可以省去我輸入「||!」的麻煩一遍又一遍地。 – chiborg 2010-11-10 10:09:33

+2

通過* empty *,OP可能意味着*空字符串*,而不是* false *。在Perl中檢查長度的標準方法。另外,不要使用'$ a'和'$ b',因爲它們是'sort'使用的包變量。 – 2010-11-10 15:16:42

+0

@Sinan:OP使用'my'聲明'$ a'和'$ b'。這些不是包變量。謝謝你的好處。 – 2010-11-10 15:37:44

8
use List::MoreUtils 'all'; 
say 'Yes' if (all { defined } $var1, $var2, $var3); 
+0

+1 - 我知道有一個更好的辦法做到這一點,但在凌晨4點懶得打擾:) – DVK 2010-11-10 15:36:25

+6

我對於不斷轉向模塊的東西,可能特別是非標準模塊深感矛盾。一方面,我不希望人們重蹈覆轍,但另一方面,我希望他們能夠熟練掌握基本的Perl功能,這些功能已經存在於核心語言本身的運作方式中。 – tchrist 2010-11-10 15:56:46

3

你的方法是可讀的,容易理解的,這意味着它很容易維護。再論用de Morgan's laws您的布爾:

if (not($a and $b and $c)) { 
    warn(qq(Not all variables are initialized!)) 
} 

這樣一來,你不是在每一個變量前面的前綴,並且不影響可讀性。您可以使用List::UtilList::MoreUtils,但它們不會增加可讀性。

正如SinanÜnür所說,如果您將變量放在哈希中,您可以通過哈希解析並列出哪些變量未被初始化。這可能是最好的,如果有很多這些變量,並且列表不斷變化。

foreach my $variable qw(a b c d e f g h i j) { 
    if (not $param{$variable}) { 
     warn qq(You didn't define $variable\n); 
    } 
} 

您可以使用Getopts::Long將參數值放入散列而不是單獨的變量中。此外,最新版本的Getopts::Long現在可以在任何陣列上運行,而不僅僅是@ARGV