有人可以解释Perl中字符串"0但是真"的含义吗?据我所知,它在整数比较中等于零,但在用作布尔值时求值为true.它是否正确?这是语言的正常行为还是在解释器中作为特殊情况处理的特殊字符串?
这是语言的正常行为.引用perlsyn
联机帮助页:
数字
0
,字符串'0'
和""
,空列表()
,并且undef
都在布尔上下文假的.所有其他值都是真的.真值的否定!
或not
返回特殊的假值.当被评估为字符串时,它被视为""
,但作为数字,它被视为0
.
因此,需要有一种方法可以0
从期望0
作为(成功)返回值返回的系统调用返回,并通过实际返回false值来指示失败案例."0 but true"
达到这个目的.
因为在Perl核心中硬编码将其视为一个数字.这是一个让Perl的约定和ioctl
惯例一起发挥作用的黑客攻击; 来自perldoc -f ioctl
:
ioctl
(和fcntl
)的返回值如下:if OS returns: then Perl returns: -1 undefined value 0 string "0 but true" anything else that number因此,Perl在成功时返回true,在失败时返回false,但您仍然可以轻松确定操作系统返回的实际值:
$retval = ioctl(...) || -1; printf "System returned %d\n", $retval;特殊字符串
"0 but true"
免于-w
投诉有关不正确的数字转换.
除了其他人所说的,它"0 but true"
是特殊的,因为它不会在数字上下文中发出警告:
$ perl -wle 'print "0 but true" + 3' 3 $ perl -wle 'print "0 but crazy" + 3' Argument "0 but crazy" isn't numeric in addition (+) at -e line 1. 3
该值0 but true
是Perl中的一个特例.虽然对于你的凡人眼睛来说,它看起来并不像一个数字,明智而且所有人都知道Perl知道它确实是一个数字.
它与Perl子例程返回0值的事实有关,假设例程失败或返回false值.
想象一下,我有一个子程序,它返回两个数字的总和:
die "You can only add two numbers\n" if (not add(3, -2)); die "You can only add two numbers\n" if (not add("cow", "dog")); die "You can only add two numbers\n" if (not add(3, -3));
第一个语句不会死,因为子例程将返回a 1
.非常好.第二个语句将会死亡,因为子程序将无法将牛添加到狗中.
而且,第三个声明?
嗯,我可以补充3
一下-3
.我得到了0
,但是即使add
子程序工作,我的程序也会死!
为了解决这个问题,Perl认为0 but true
是一个数字.如果我的附加子程序返回不只是0,但0,但真正的,我的第三条语句会工作.
但是0是真的数字零吗?试试这些:
my $value = "0 but true"; print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "\n"; print "Multiply it by 1,000,000: " . 1_000_000 * $value . "\n";
是的,它是零!
该指数子程序是一个非常古老的一块的Perl和概念之前就已经存在0,但真正在周围.假设返回位于字符串中的子字符串的位置:
index("barfoo", "foo"); #This returns 3 index("barfoo", "bar"); #This returns 0 index("barfoo", "fu"); #This returns ...uh...
最后一个法则返回一个-1
.这意味着如果我这样做:
if ($position = index($string, $substring)) { print "It worked!\n"; } else { print "If failed!\n"; }
正如我通常使用标准功能一样,它不起作用.如果我像在第二个语句中那样使用"barfoo"和"bar",则该else
子句将执行,但如果我在第三个中使用"barfoo"和"fu",则该if
子句将执行.不是我想要的.
但是,如果index
子例程返回0但对于第二个语句和undef
第三个语句都返回true,则my if
/ else
clause将起作用.
您可能还会看到Perl代码中使用的字符串"0E0",它意味着相同的东西,其中0E0仅表示以指数表示法写入的0.但是,由于Perl仅将"0","或undef视为false,因此在布尔上下文中计算结果为true.
它在Perl的源代码中是硬编码的,特别是在numeric.c中的Perl_grok_number_flags中.
读取该代码我发现字符串"infinity"(不区分大小写)也通过了looks_like_number测试.我不知道.
在整数上下文中,它的计算结果为0(字符串开头的数字部分),为零.在标量上下文中,它是一个非空值,所以它是真的.
if (int("0 but true")) { print "zero"; }
(没有输出)
if ("0 but true") { print "true"; }
(打印真实)
0表示Perl中的false(以及与C相关的其他语言).在大多数情况下,这是一种合理的行为.其他语言(例如Lua)将0视为true,并提供另一个令牌(通常为nil或false)来表示非真值.
Perl方式不能很好地工作的一种情况是当你想要返回一个数字时,或者如果函数由于某种原因失败,则返回false值.例如,如果您编写的函数从文件中读取一行并返回该行上的字符数.该函数的常见用法可能是:
while($c = characters_in_line($file)){ ... };
请注意,如果特定行上的字符数为0,则while循环将在文件结束之前结束.所以characters_in_line函数应该是特殊情况0字符,而是返回'0但是为true'.这样,该函数将在while循环中按预期工作,但如果它被用作数字,也会返回正确的答案.
请注意,这不是语言的内置部分.相反,它利用了Perl将字符串解释为数字的能力.因此有时会使用其他刺痛. 例如,DBI使用"0E0".在数值上下文中计算时,它们返回0,但在布尔上下文中为false.
事情是错误的:
""
.
"0"
.
与那些串联的事情.
"0 but true"
不是其中之一,所以这不是假的.
此外,Perl返回"0 but true"
一个预期数字的位置,以便发信号表示函数成功,即使它返回零.sysseek就是这样一个函数的一个例子.由于该值预计将用作数字,因此Perl被编码为将其视为数字.因此,当它用作数字时不会发出警告,并looks_like_number("0 but true")
返回true.
其他"真正的零"可以在http://www.perlmonks.org/?node_id=464548找到.