我目前使用以下Perl来检查变量是否已定义并包含文本。我必须首先检查defined
以避免“未初始化的值”警告:
if (defined $name && length $name > 0) {
# do something with $name
}
有没有更好的(大概更简洁)的方式来编写此代码?
我目前使用以下Perl来检查变量是否已定义并包含文本。我必须首先检查defined
以避免“未初始化的值”警告:
if (defined $name && length $name > 0) {
# do something with $name
}
有没有更好的(大概更简洁)的方式来编写此代码?
Answers:
您经常会看到对定义性的检查,因此您不必处理使用undef值的警告(在Perl 5.10中,它告诉您有问题的变量):
Use of uninitialized value $name in ...
因此,为了避免这种警告,人们提出了各种各样的代码,该代码开始看起来像是解决方案的重要组成部分,而不是原来的泡泡糖和胶带。有时,最好通过显式关闭要避免的警告来显示您的操作:
{
no warnings 'uninitialized';
if( length $name ) {
...
}
}
在其他情况下,请使用某种空值代替数据。使用Perl 5.10的define-or运算符,您可以给出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
(并且应该这样做),则将得到以下建议:
在字符串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 )
是等效的。
如果可以将未定义的值替换为空字符串,可以使用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 //= "";
Sinan发布的内容。
$name ||= "";
undef
和""
,她应该只是改变一个到另一个,并使用一个单一的测试。在一般情况下,这是行不通的,因为发布的其他解决方案要好得多,但是在这种情况下,代码会很整洁。我应该改写我的答案以使其更清楚吗?
并非总是可能以简单而优雅的方式来做重复的事情。
当拥有可以在许多项目中复制的通用代码时,只需执行您通常会做的事情:
搜索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
。
&
在调用函数时使用符号。因此,我倾向于不依靠原型来完成所有工作。我想我可以在错误消息中添加“并在子调用中使用&sigil退出,除非您确实如此”。
出色的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
}
这与您的原始版本并不完全相同,因为如果$name
数字值为0或字符串'0'
,它也会返回false ,但在所有其他情况下的行为相同。
在perl 5.10(或更高版本)中,适当的方法是改为使用define-or运算符:
use feature ':5.10';
if (length ($name // '')) {
# do something with $name
}
这将根据是否$name
定义而不是是否正确来决定获取长度的信息,因此0 /'0'
可以正确处理这些情况,但它需要的Perl版本比许多人都可用。
length undef
返回undef,而不是警告并返回0。在布尔上下文中,undef与0一样为false,因此,如果您的目标是v5.12或更高版本,则可以编写if (length $name) { ... }