2015-09-04 40 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"; 
    } 

    ... 
}