Вы часто видите проверку на определенность, поэтому вам не нужно иметь дело с предупреждением об использовании значения undef (а в Perl 5.10 он сообщает вам ошибочную переменную):
Use of uninitialized value $name in ...
Итак, чтобы обойти это предупреждение, люди придумывают всевозможные коды, и этот код начинает выглядеть как важная часть решения, а не как жевательная резинка и клейкая лента. Иногда лучше показать, что вы делаете, явно отключив предупреждение, которого вы пытаетесь избежать:
{
no warnings 'uninitialized';
if( length $name ) {
...
}
}
В других случаях используйте какое-то нулевое значение вместо данных. С помощью оператора defined-or Perl 5.10 вы можете указать length
явную пустую строку (определенную и вернуть нулевую длину) вместо переменной, которая вызовет предупреждение:
use 5.010;
if( length( $name // '' ) ) {
...
}
В Perl 5.12 это немного проще, потому length
что значение undefined также возвращает undefined . Это может показаться немного глупым, но это нравится математику, которым я, возможно, хотел бы быть. Это не вызывает предупреждения, поэтому этот вопрос существует.
use 5.012;
use warnings;
my $name;
if( length $name ) {
...
}
length undef
возвращается undef вместо предупреждения и возврата 0. В логическом контексте undef так же ложно, как и 0, поэтому, если вы ориентируетесь на версию 5.12 или новее, вы можете просто написатьif (length $name) { ... }
Как указывает мобрул, вы можете использовать следующее для небольшой экономии:
if (defined $name && $name ne '') { # do something with $name }
Вы можете отказаться от определенной проверки и получить что-то еще более короткое, например:
if ($name ne '') { # do something with $name }
Но в случае, когда
$name
не определено, хотя логический поток будет работать так, как задумано, если вы используетеwarnings
(а вы должны использовать), вы получите следующее предупреждение:Итак, если есть вероятность, что это
$name
может не быть определено, вам действительно нужно в первую очередь проверить определенность, чтобы избежать этого предупреждения. Как указывает Синан Юнюр, вы можете использовать Scalar :: MoreUtils, чтобы получить код, который делает именно это (проверяет определенность, а затем проверяет нулевую длину) из коробки, с помощьюempty()
метода:use Scalar::MoreUtils qw(empty); if(not empty($name)) { # do something with $name }
источник
Во-первых, поскольку
length
всегда возвращает неотрицательное число,if ( length $name )
и
if ( length $name > 0 )
эквивалентны.
Если вы согласны с заменой неопределенного значения пустой строкой, вы можете использовать
//=
оператор Perl 5.10, который присваивает RHS LHS, если LHS не определен:#!/usr/bin/perl use feature qw( say ); use strict; use warnings; my $name; say 'nonempty' if length($name //= ''); say "'$name'";
Обратите внимание на отсутствие предупреждений о неинициализированной переменной как
$name
присваивается пустая строка, если она не определена.Однако, если вы не хотите зависеть от установки 5.10, используйте функции, предоставляемые Scalar :: MoreUtils . Например, приведенное выше можно записать как:
#!/usr/bin/perl use strict; use warnings; use Scalar::MoreUtils qw( define ); my $name; print "nonempty\n" if length($name = define $name); print "'$name'\n";
Если вы не хотите тупить
$name
, используйтеdefault
.источник
length( $name // '' )
.//
и//=
, возможно, являются наиболее полезными из существующих специализированных операторов.length
теперь может возвращаться что-то, что не является числом (но не NaN;)В тех случаях, когда мне все равно,
undef
равна ли переменная или равна''
, я обычно резюмирую ее как:$name = "" unless defined $name; if($name ne '') { # do something with $name }
источник
$name //= "";
, что написал Синан.$name ||= "";
undef
и""
, она должна просто заменить одно на другое и использовать один тест. Это не сработает в общем случае, для которого другие опубликованные решения намного лучше, но в этом конкретном случае приводит к аккуратному коду. Стоит ли перефразировать свой ответ, чтобы было понятнее?Ты мог бы сказать
$name ne ""
вместо
length $name > 0
источник
Не всегда возможно делать повторяющиеся вещи просто и элегантно.
Просто делайте то, что делаете всегда, когда у вас есть общий код, который реплицируется во многих проектах:
Выполните поиск по CPAN, возможно, у кого-то уже есть код для вас. Для этой проблемы я нашел Scalar :: MoreUtils .
Если вы не найдете на CPAN того, что вам нравится, создайте модуль и вставьте код в подпрограмму:
package My::String::Util; use strict; use warnings; our @ISA = qw( Exporter ); our @EXPORT = (); our @EXPORT_OK = qw( is_nonempty); use Carp qw(croak); sub is_nonempty ($) { croak "is_nonempty() requires an argument" unless @_ == 1; no warnings 'uninitialized'; return( defined $_[0] and length $_[0] != 0 ); } 1; =head1 BOILERPLATE POD blah blah blah =head3 is_nonempty Returns true if the argument is defined and has non-zero length. More boilerplate POD. =cut
Затем в своем коде назовите это:
use My::String::Util qw( is_nonempty ); if ( is_nonempty $name ) { # do something with $name }
Или , если вы возражаете прототипы и не возражают против дополнительных скобок, пропустить прототип в модуле, и назвать его как:
is_nonempty($name)
.источник
Scalar::MoreUtils
.&
сигилы при вызове функций. Поэтому я предпочитаю не полагаться на прототипы, чтобы сделать всю работу. Полагаю, я мог бы добавить к сообщению об ошибке «и прекратить использование символа & для дополнительных вызовов, если вы действительно это не имеете в виду».Отличная библиотека Type :: Tiny предоставляет основу для встраивания проверки типов в ваш код Perl. То, что я здесь показываю, является лишь тончайшей вершиной айсберга и использует Type :: Tiny самым упрощенным и ручным способом.
Обязательно ознакомьтесь с Type :: Tiny :: Manual для получения дополнительной информации.
use Types::Common::String qw< NonEmptyStr >; if ( NonEmptyStr->check($name) ) { # Do something here. } NonEmptyStr->($name); # Throw an exception if validation fails
источник
Как насчет
if (length ($name || '')) { # do something with $name }
Это не совсем эквивалентно вашей исходной версии, так как она также вернет false, если
$name
это числовое значение 0 или строка'0'
, но будет вести себя так же во всех других случаях.В Perl 5.10 (или новее) подходящим подходом было бы использование вместо этого оператора defined-or:
use feature ':5.10'; if (length ($name // '')) { # do something with $name }
Это решит, что получить длину, в зависимости от того
$name
, определено ли это, а не от того, истинно ли это, поэтому 0 /'0'
будет обрабатывать эти случаи правильно, но для этого требуется более свежая версия perl, чем есть у многих людей.источник
источник