如何在Perl中检查函数参数是否为字符串或数组

4

我正在尝试使用Perl编写自定义的validateParameter函数。

我有以下代码,也可以正常工作:

sub validateParameter {
    my ($args, $list) = @_;
    
    if ( ref($list) eq "ARRAY" ) {

        foreach my $key (@$list) {
            if ( not defined $args->{$key} ) {
                die "no $key given!";
            }
        }
    } 
    #elsif ( check if string ) {
    #}
}

我想以以下方式调用我的函数:
validateParameter({ hallo => "Welt", test => "Blup"},  ["hallo", "test"]);

但我也想像这样调用我的函数:

validateParameter({ hallo => "Welt", test => "Blup"},  "hallo");

我知道Perl只有以下三种数据类型(标量,哈希和数组)。但也许有一种聪明的方法来检查一个变量是否为字符串。
如何检查给定的参数是否为字符串?

你是指与“数字”相对的“字符串”吗?还是与“数组引用 /哈希引用/…”相反的“字符串”?然后 ref 就是要走的路线(就像你已经做过的那样)。它对于简单的非 ref 标量(比如你的 $list)返回一个空字符串。 - PerlDuck
哦,好的,是我的错:D。这篇文章已经完成了。谢谢@PerlDuck。 - FrankTheTank_12345
3个回答

5
更新:我不知何故错过了问题的结尾。只需测试ref($list) eq 'ARRAY'大多数情况下都可以工作,但为了正确地允许超载对象,您应该尝试取消引用参数:
if ( eval { \@$list } ) {
    # it was an array 
}
else {
    # assume it is a string
}

原始答案:

您可以检查参数的多个属性:

if ( ! defined $param ) {
    # undefined
}
elsif ( defined Scalar::Util::blessed($param) ) {
    # object
}
elsif ( ref $param ) {
    # reference (return of ref will give the type)
}
elsif ( length do { no warnings "numeric"; $param & '' } ) {
    # number
}
else {
    # string
}

但是所有这些(除了可能的定义检查)都有点违背了Perl自动转换为所需类型的目的,并且会限制可以传递的内容(例如,需要数字的字符串或双重变量,或者需要字符串、数字或引用的重载对象,或者像$!这样的绑定变量或魔术变量)。

您可能还想看看Params::Validate能做什么。


注意:如果$listundef,则\@$list将自动创建$list,因此如果这是有效输入,请先处理undef - ikegami
@ikegami 我猜 undef 更像是一个空数组而不是一个未定义的“字符串” - ysth

1
不要基于参数的“类型”来设置行为,因为实际上并没有这样的东西。如果使用基于类型的多态性,会遇到问题,因为Perl值通常具有多种类型。例如,“123”产生的标量存储为字符串,但是Perl不将其与未存储为字符串的标量区分开来。标量可以包含数字和缓存的数字字符串(例如,my $i = 123; "".$i;)。标量可以同时包含数字和字符串(不是数字字符串化的字符串)。其中一些常见的示例是$!和!1。重载字符串化的对象的引用也是一个有用的字符串(例如,DateTime->now)。对数组的引用可能会重载%{}以用作哈希引用。对哈希的引用可能会重载@{}以用作数组引用。还有更多。

0

不,没有办法检查标量是否为字符串,因为Perl根据上下文进行隐式类型转换。如果您将数字作为函数的第二个参数,并在需要字符串的上下文中使用它,则会自动将其转换为字符串。因此,只需检查ref($list)是否为空-在这种情况下,$list不是引用,因此它是一个字符串或数字,您不需要区分这两者。


3
好的,有一个核心模块 Scalar::Util::looks_like_number 可以用来检测数字,但我认为这不是原帖作者想要的。 - PerlDuck
请注意,ref($list)将返回对字符串化重载的对象为真。这意味着,即使$url可以用作字符串,如果使用ref,则my $url = URI->new('http://stackoverflow.com/'); validateParameter({ hallo => "Welt", test => "Blup"}, $url);将失败。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接