我对以下perl片段的结果感到好奇:
my $var1 ;
my $var2 ;
if( $var1 eq $var2 ) {
print "yes";
} else {
print "no";
}
和
my $var1 ;
my $var2 = "";
if( $var1 eq $var2 ) {
print "yes";
} else {
print "no";
}
结果是yes
(Perl 5.16)。
与javascript规范不同,有明确的等式比较算法描述(http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3),perl doc for Equality Operators说:
如果左参数的字符串等于右参数,则二进制“eq”返回true。
但是字符串相等的定义是什么?
答案 0 :(得分:7)
你对字符串相等的定义没有问题。你似乎没有把头包裹起来的是字符串化的概念。在这种特殊情况下,undef
字符串化为''
。
答案 1 :(得分:2)
Perl具有单态运算符(主要是)和上下文多态数据类型。
这意味着运营商决定数据的表示方式。 eq
运算符用于字符串相等。 ==
运算符用于数字相等。将==
应用于字符串时,会将其视为数字。将eq
应用于数字时,它们将被视为字符串。每个内部转换都遵循一套非常具体的规则。
因此,当您将一个字符串运算符应用于一对值时,这些值将被视为字符串。将数值运算符应用于一对值时,它们将被视为数字。
在第二个示例中,$var1
包含undef
,$var2
包含空字符串。比较$var1 eq $var2
时,字符串化规则将应用于操作数。 $var2
已经是一个字符串。但是$var1
必须先进行字符串化才能进行比较。未定义值的字符串化规则是将其视为空字符串。因此$var1 eq $var2
运算符将eq
视为'' eq ''
,也就是说,空字符串eq为空字符串。
TRUE。
注意:在现代版本的Perl中,在字符串式操作中使用未定义的标量变量只会导致操作持续时间的字符串化;容器中的基础数据不会改变。 (见perldata
)。
perldata是此主题的一个资源。
答案 2 :(得分:0)
你的定义问题已由DavidO回答,但(可能)最重要的信息是TLP的评论 - 你应该总是在每个脚本的顶部使用这两个:
use strict;
use warnings;
在这种情况下相关的是use warnings
,它将产生以下警告:
Use of uninitialized value $var1 in string eq
有些程序更进一步 - 这将导致程序因此而死:
use warnings FATAL => 'all';
您正在使用eq比较变量,这意味着您正在进行字符串比较。字符串比较需要两个字符串,但是您提供了一个未定义的变量(声明的变量,但未定义,因此不是字符串)。这不是很干净,因为您使用具有无效输入的运算符。如果你想知道变量是否不同,而不仅仅是它们(可能或不可能)代表的字符串,你就不会使用这样的字符串比较。
它的工作原理是因为Perl知道你想比较字符串(eq)所以它假设你不关心变量没有赋值的事实。未定义的变量被转换为空字符串(临时),然后进行比较。 (实际上,变量本身并没有被转换,在比较之后它仍然是未定义的,但这并不重要。)
当然,这种假设可能是错误的,您的代码中可能存在错误。因此,在比较之前检查无效输入会更好。
你不关心undef和'''' (你知道为什么)。
您可以显式比较空字符串而不是undef。正在阅读你的代码的另一位程序员将知道发生了什么(不会认为那里有一个错误)。
if (($var1 // q()) eq ($var2 // q()))
...
在许多情况下,您可能真的关心undef。
例如,您的脚本可能需要一些输入(可能是一个哈希),如果该输入变量是一个空字符串,那就没关系,但是如果它是undef(可能在输入哈希中找不到),这将是一个错误。
if (!defined($var1))
{
die "Input data missing, can't continue!";
}
if ($var1 eq $var2)
...