无论

时间:2016-10-16 17:34:20

标签: perl

我的剧本中有以下几行:

my $spec = shift;
if (!defined $spec) {
    return ("Invalid specification", undef);
}
$spec = "$spec" // '';

我自然希望在传递undef时,会在数组中返回警告Invalid specification,第二项为undef。相反,检查通过了,我收到一条控制台消息,警告我下一行Use of uninitialized value $spec in string

$spec是一个带有字符串和数字重载的对象,不幸的是这样编写,试图在这个特定的子例程中测试真实性(例如通过if ($spec))会导致深度递归和段错误。

虽然我 感兴趣的是,为什么,确切地说,这种情况正在发生,我更多对如何使其停止感兴趣发生。我想消除控制台警告,最好没有no warnings qw/uninitialized/。这是可能的,如果是这样,我该怎么做?

1 个答案:

答案 0 :(得分:7)

您说$specstring overloading的对象。

如果是这种情况,那么在检查它是否被定义之前,你需要将它强制转换为String形式:

if (! defined overload::StrVal($spec)) {

每月更正

正如在StrVal中指出的那样,没有强制重载的字符串化:

  

过载:: StrVal(ARG)

     

在没有stringify重载的情况下给出arg的字符串值。如果你使用它来获取引用的地址(用于检查两个引用是否指向同一个东西)那么你最好使用Scalar :: Util :: refaddr(),这样会更快。

因此,为了实现这一点,请尝试他的另一个建议:

  

“$ spec”捕获警告并检测未初始化的var警告。最好在类中添加一个方法来测试返回undef的任何情况。

以下演示了这种方法:

#!/usr/bin/env perl

use strict;
use warnings;

use Test::More tests => 2;

my $obj_str_defined = StringOverloaded->new("has value");
my $obj_str_undef   = StringOverloaded->new(undef);

ok( is_overloaded_string_defined($obj_str_defined), qq{\$obj_str_defined is defined} );
ok( !is_overloaded_string_defined($obj_str_undef),  qq{\$obj_str_undef is undef} );

sub is_overloaded_string_defined {
    my $obj = shift;

    my $is_str_defined = 1;

    local $SIG{__WARN__} = sub {
        $is_str_defined = 0 if $_[0] =~ /Use of uninitialized value \$obj in string/;
    };

    my $throwaway_var = "$obj";

    return $is_str_defined;
}

{
    # Object with string overloading
    package StringOverloaded;

    use strict;
    use warnings;

    use overload (
        '""' => sub {
            my $self = shift;
            return $$self;    # Dereference
        },
        fallback => 1
    );

    sub new {
        my $pkg  = shift;
        my $val  = shift;
        my $self = bless \$val, $pkg;

        return $self;
    }
}

输出:

1..2
ok 1 - $obj_str_defined is defined
ok 2 - $obj_str_undef is undef