2015-09-04 41 views
5

我有一個原型這樣的子程序:子程序與哈希和可選的標量參數

sub printFoo(%) { 
    my (%hashFoo)[email protected]_; 
    # do stuff with the hash 
} 

但我想在這樣的第二標參數可選通:

sub printFoo(%;$) { 
    my (%hashFoo,$optionalArg)[email protected]_; 
    # do stuff with the hash and the optional arg 
} 

我明白,在警告模式下,這是一個禁忌,但我不知道爲什麼。

我想我可以使用全局變量標誌,但任何關於如何優雅地完成這種類型的函數簽名的建議?

+1

您可以將引用傳遞給散列而不是散列本身 –

+5

原型不是用於創建函數簽名,而是讓函數具有類似於內置函數的行爲。關於原型的一般建議是不要使用它們。該函數將把所有@_變成%hashFoo。您可以檢查@_的長度並在將其解包到%hashFoo之前​​彈出可選參數。 – xxfelixxx

+1

最簡潔的解決方案是將可選參數包含在(foo => bar,baz => 123,special => 3)params的其餘部分中,並且專門處理特殊參數(如果它是沒有通過) – xxfelixxx

回答

4

我不知道這是否算作優雅,但...

sub printFoo { 
    my $optionalArg; 
    if (@_ % 2 != 0) { 
     $optionalArg = pop @_; 
    } 
    my %hashFoo = @_; 
    ... 
} 

原型與散列引用也將工作。您仍然可以使用散列來調用函數,但是您必須記住您的子項將第一個散列參數作爲散列引用來接收。

sub printFoo (\%;$) { # call as printFoo %foo or printFoo %foo, 42 
    my ($hashFooRef, $optionalArg) = @_; 
    my %hashFoo = %$hashFooRef; 
    ... 
} 
1

我同意Hakon Haegland關於使用散列引用。爲了得到不止一個你可以選擇的論點,你需要傳遞多個標量,而不是本質上是一個列表,然後是其他東西。

我認爲這與你是否應該使用原型無關。警告系統通過標記這件事對你有利,但我99.44%確定即使丟棄了原型,它也不會工作。您仍然不會在可選參數中產生一個值。

2

典雅的處理可選參數:

sub do_something { 
    my (%params) = @_; 
    my $debug = delete $params{debug} || 0; 
    # do something with %params... 
} 
+0

這幾乎是我在我所有的模塊中親自做的。我接受所有參數的單個href(而不是哈希)。有時我會接受一個額外的cref回調作爲輔助參數,但我更願意接受一個結構中的所有內容。 – stevieb

2

如果使用哈希裁判正如其他人建議作爲第一個參數,然後檢查ARGS自己是被接受後,是微不足道的:

use strict; 
use warnings; 

my %hash = (a => 1, b => 2,); 
my $scalar = 1; 

printFoo(\%hash, $scalar); 

sub printFoo { 
    my ($href, $opt) = @_; 

    if(ref $href ne 'HASH' || $opt && ref \$opt ne 'SCALAR'){ 
     die "Usage: printFoo(hashref, optional_scalar)\n"; 
    } 

    ... 
}