В 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
не может быть определено, действительно нужно проверить definedness в первую очередь для того, чтобы избежать этого предупреждения. Как указывает Sinan Ünür, вы можете использовать Скаляр::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, используйте функции, предоставляемые Скаляр:: 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, кто-то уже может иметь код для вас. Для этого вопроса я нашел Скаляр::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)
.
отличная библиотека Тип::Крошечная предоставляет фреймворк, с помощью которого можно построить проверку типов в коде 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, чем у многих людей.
if ($name ) { #since undef and '' both evaluate to false #this should work only when string is defined and non-empty... #unless you're expecting someting like $name="0" which is false. #notice though that $name="00" is not false }