我目前使用以下Perl来检查变量是否已定义并包含文本。我必须首先检查defined
以避免'未初始化的值'警告:
if (defined $name && length $name > 0) {
# do something with $name
}
有没有更好的(可能更简洁)的方式来写这个?
答案 0 :(得分:70)
您经常会看到对定义性的检查,因此您不必处理使用undef值的警告(在Perl 5.10中它会告诉您有问题的变量):
Use of uninitialized value $name in ...
因此,为了解决这个警告,人们会提出各种代码,而且代码开始看起来像解决方案的一个重要部分,而不是泡泡糖和胶带。有时,最好通过明确地关闭您要避免的警告来显示您正在做的事情:
{
no warnings 'uninitialized';
if( length $name ) {
...
}
}
在其他情况下,请使用某种空值而不是数据。使用Perl 5.10's defined-or operator,您可以为length
提供一个显式空字符串(已定义,并返回零长度),而不是将触发警告的变量:
use 5.010;
if( length( $name // '' ) ) {
...
}
在Perl 5.12中,它更容易因为length
on an undefined value also returns undefined。这可能看起来有点愚蠢,但这让我想成为的数学家高兴。这不会发出警告,这就是存在这个问题的原因。
use 5.012;
use warnings;
my $name;
if( length $name ) { # no warning
...
}
答案 1 :(得分:23)
正如专栏所示,您可以使用以下内容代替小额节省:
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
}
答案 2 :(得分:14)
首先,由于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
未定义,则为#!/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";
分配空字符串。
但是,如果您不想依赖于安装5.10,请使用Scalar::MoreUtils提供的功能。例如,以上内容可以写成:
$name
如果您不想破坏default
,请使用{{1}}。
答案 3 :(得分:6)
如果我不关心变量是undef
还是等于''
,我通常会将其概括为:
$name = "" unless defined $name;
if($name ne '') {
# do something with $name
}
答案 4 :(得分:1)
你可以说
$name ne ""
而不是
length $name > 0
答案 5 :(得分:1)
并不总是能够以简单而优雅的方式做重复的事情。
当您拥有可在多个项目中复制的公共代码时,只需执行您经常执行的操作:
搜索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)
。
答案 6 :(得分:1)
优秀的库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
答案 7 :(得分:-2)
怎么样
if (length ($name || '')) {
# do something with $name
}
这与原始版本不完全相同,因为如果$name
是数字值0或字符串'0'
,它也会返回false,但在所有其他情况下表现相同。
在perl 5.10(或更高版本)中,适当的方法是使用defined-or运算符:
use feature ':5.10';
if (length ($name // '')) {
# do something with $name
}
这将根据是否定义$name
来确定获取长度的长度,而不是它是否为真,因此0 / '0'
将正确处理这些情况,但它需要更新版本perl比很多人都有。
答案 8 :(得分:-3)
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 }