В Perl, как я могу кратко проверить, определена ли переменная $и содержит строку ненулевой длины?
в настоящее время я использую следующий Perl, чтобы проверить, определена ли переменная и содержит текст. Я должен проверить defined
во-первых, чтобы избежать "неинициализированного значения" предупреждение:
if (defined $name && length $name > 0) {
# do something with $name
}
есть ли лучший (предположительно более краткий) способ написать это?
9 ответов:
вы часто видите проверку на определенность, поэтому вам не нужно иметь дело с предупреждением об использовании значения undef (и в Perl 5.10 он сообщает вам оскорбительную переменную):
Use of uninitialized value $name in ...
Итак, чтобы обойти это предупреждение, люди придумывают всевозможные коды, и этот код начинает выглядеть как важная часть решения, а не жевательная резинка и клейкая лента, что это такое. Иногда лучше показать, что вы делаете, явно отключив предупреждение о том, что вы пытаясь избежать:
{ no warnings 'uninitialized'; if( length $name ) { ... } }
в других случаях используйте какое-то нулевое значение вместо данных. С в Perl 5.10 оператор, вы можете дать
length
явная пустая строка (определенная и возвращающая нулевую длину) вместо переменной, которая вызовет предупреждение:use 5.010; if( length( $name // '' ) ) { ... }
в Perl 5.12, это немного проще, потому что
length
на неопределенное значение также возвращает undefined. Это может показаться немного глупой, но что радует математик я хотел бы быть. Это не выдает предупреждение, поэтому этот вопрос существует.use 5.012; use warnings; my $name; if( length $name ) { # no warning ... }
как указывает mobrule, вы можете использовать следующее вместо небольшой экономии:
if (defined $name && $name ne '') { # do something with $name }
вы можете отказаться от определенной проверки и получить что-то еще короче, например:
if ($name ne '') { # do something with $name }
но в том случае, когда
$name
не определен, хотя логический поток будет работать так же, как и предполагалось, если вы используетеwarnings
(и вы должны), то вы получите следующее предупреждение:Use of uninitialized value in string neтак что, если есть шанс, что
$name
не может быть определено, действительно нужно проверить определенность в первую очередь, чтобы избежать этого предупреждения. Как указывает Синан Унюр, вы можете использовать Скаляр::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
.
в тех случаях, когда мне все равно, является ли переменная
undef
или равно''
, Я обычно резюмирую это так:$name = "" unless defined $name; if($name ne '') { # do something with $name }
не всегда можно делать повторяющиеся вещи простым и элегантным способом.
просто делайте то, что вы всегда делаете, когда у вас есть общий код, который реплицируется во многих проектах:
Поиск 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 }
или если вы возражаете против прототипов и не возражаете против дополнительных parens, пропустите прототип в модуле и назовите его так:
is_nonempty($name)
.
отличная библиотека Тип::Крошечная предоставляет фреймворк, с помощью которого можно построить проверку типов в коде Perl. То, что я показываю здесь, является только самой тонкой вершиной айсберга и использует Type::Tiny самым упрощенным и ручным способом.
будьте уверены, чтобы проверить Тип::Малолетка::Инструкция для получения дополнительной информации.
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, чем у многих людей.