В настоящее время я использую следующий Perl, чтобы проверить, определена ли переменная и содержит текст. Сначала я должен проверить defined
, чтобы избежать предупреждения "неинициализированное значение":
if (defined $name && length $name > 0) {
# do something with $name
}
Есть ли лучший (предположительно более краткий) способ написать это?
Вы часто видите проверку на определенность, поэтому вам не нужно иметь дело с предупреждением об использовании значения 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 также возвращает 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
не может быть определен, вам действительно нужно проверить определенность в первую очередь, чтобы избежать этого предупреждения. Как указывает Sinan Ünür, вы можете использовать Scalar:: MoreUtils, чтобы получить код, который делает именно это (проверяет определенность, затем проверяет нулевую длину) из коробки, с помощью метода empty()
:
use Scalar::MoreUtils qw(empty);
if(not empty($name)) {
# do something with $name
}
Во-первых, поскольку length
всегда возвращает неотрицательное число,
if ( length $name )
и
if ( length $name > 0 )
эквивалентны.
Если вы согласны с заменой значения undefined пустой строкой, вы можете использовать оператор 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
присваивается пустая строка, если она undefined.
Однако, если вы не хотите зависеть от установки 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";
Если вы не хотите clobber $name
, используйте default
.
length( $name // '' )
.
В тех случаях, когда мне не важно, является ли переменная undef
или равна ''
, я обычно суммирую ее как:
$name = "" unless defined $name;
if($name ne '') {
# do something with $name
}
$name //= "";
это именно то, что опубликовал Синан.
$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
}
Или, если вы возражаете против прототипов и не возражаете против дополнительных парсеров, пропустите прототип в модуле и назовите его так: is_nonempty($name)
.
Scalar::MoreUtils
.
Можно сказать
$name ne ""
вместо
length $name > 0
my %hash ;
$hash{"what"} = "What";
$hash{"how"} = "How";
my $word = $hash{"now"};
print $word;
if (! $word) {
print "Catch Ya\n";
}
else {
print $word ;
}
Как насчет
if (length ($name || '')) {
# do something with $name
}
Это не совсем эквивалентно исходной версии, так как оно также вернет false, если $name
- это числовое значение 0 или строка '0'
, но будет вести себя одинаково во всех остальных случаях.
В perl 5.10 (или более поздней версии) подходящий подход будет заключаться в том, чтобы использовать вместо него определенный или оператор:
use feature ':5.10';
if (length ($name // '')) {
# do something with $name
}
Это решит, что получить длину, основанную на определении $name
, а не как true, поэтому 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 }
length undef
возвращает undef вместо предупреждения и возврата 0. В логическом контексте undef так же ложно, как 0, поэтому, если вы ориентируетесь на v5.12 или более позднюю, вы можете просто написать,if (length $name) { ... }