#perl
#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)
например, путем) приводит к глубокой рекурсии и segfault.
Хотя меня интересует, почему именно это происходит, меня больше интересует, как заставить это перестать происходить. Я хочу устранить предупреждение консоли, предпочтительнее без no warnings qw/uninitialized/
. Возможно ли это, и если да, то как мне это сделать?
Комментарии:
1. Попробуйте
$spec //= ''
или$spec = defined $spec ? "$spec" : ''
2. Отличный вопрос.
Ответ №1:
Вы говорите, что $spec
это объект с перегрузкой строки.
Если это так, то вам нужно принудительно преобразовать ее в строковую форму, прежде чем проверять, определена ли она:
if (! defined overload::StrVal($spec)) {
Исправление для каждого ysth
Как указано в ysth в StrVal, не вызывает перегруженную строку:
перегрузка::StrVal(arg)
Выдает строковое значение аргумента, как при отсутствии перегрузки stringify . Если вы используете это, чтобы получить адрес ссылки (полезно для проверки, указывают ли две ссылки на одно и то же), то вам может быть лучше использовать 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
Комментарии:
1. Я не думаю, что это то, что здесь требуется :
overload::StrVal(arg) Gives the string value of arg as in the absence of stringify overloading.
. То есть она вернет ссылку на объект в строковой форме, например, Foo=HASH(0xdeadbeef)2. @ysth Я думаю, вы правы. Знаете ли вы правильный метод принудительного формирования строки без использования конкатенации?
3. «$ spec» перехватывает предупреждения и обнаруживает неинициализированное предупреждение var. Лучше добавить метод в класс для проверки любого случая, возвращающего undef.
4. @ysth расширил исправление. Спасибо, что указали на это.