在Perl中,“0但真”意味着什么?
有人可以解释什么string“0但真”意味着在Perl中? 据我所知,它在整数比较中等于零,但在作为布尔值使用时计算为true。 它是否正确? 这是一种正常的语言行为吗?或者这是一个特殊的string在解释器中被视为一个特殊情况?
这是语言的正常行为。 引用perlsyn
:
数字
0
,string'0'
和""
,空列表()
和undef
在布尔上下文中都是假的。 所有其他值是真实的。 否定一个真正的价值!
或者not
返回一个特殊的错误值。 当作为一个string进行评估时,它被视为""
,但是作为一个数字,它被视为0
。
因此,需要有一种方法可以从系统调用返回0
,这个系统调用预期返回0
作为(成功的)返回值,并且通过实际返回一个错误值给出一个失败的情况。 "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;
特殊的string
"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中是一个特例。 尽pipe对于你的眼睛来说,它看起来并不像一个数字,聪明,所有知道的Perl都明白它确实是一个数字。
这与Perl子程序返回0值时的事实有关,假定例程失败或返回一个假值。
想象一下,我有一个子程序返回两个数字的总和:
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));
第一个语句不会死,因为子例程会返回1
。 那很好。 第二个声明将会死亡,因为子程序将无法将牛添加到狗 。
而且,第三个陈述?
嗯,我可以加3
到-3
。 我只是得到0
,但是即使add
子程序工作,我的程序将会死亡!
为了解决这个问题,Perl认为0 but true
是一个数字。 如果我的add子程序不仅返回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的概念之前, 但是真正的是。 假设返回位于string中的子串的位置:
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
语句就会执行,但是如果我像第三个语句else
使用“barfoo”和“fu”, if
语句就会执行。 不是我想要的。
但是,如果index
子例程返回0,但第二个语句为true ,第三个语句为undef
,那么我的if
/ else
子句就可以工作。
你也可以在Perl代码中看到string“0E0” ,这意味着同样的事情,其中0E0仅仅意味着用指数表示法写0。 但是,由于Perl仅将“0”,“”或undef视为false,因此在布尔上下文中计算结果为true。
它在Perl的源代码中被硬编码,特别是在numeric.c中的Perl_grok_number_flags中 。
读取代码,我发现string“无穷大”(不区分大小写)也通过了looks_like_numbertesting。 我不知道。
在整数上下文中,它的计算结果为0(string开头的数字部分)并且为零。 在标量的情况下,这是一个非空的值,所以这是真的。
-
if (int("0 but true")) { print "zero"; }
(没有输出)
-
if ("0 but true") { print "true"; }
(打印真实)
0表示Perl中的错误(以及与C相关的其他语言)。 大多数情况下,这是一个合理的行为。 其他语言(例如Lua)将0视为true,并提供另一个标记(通常为零或为假 )来表示非真值。
Perl方法不能很好地工作的一种情况是当你想要返回一个数字,或者如果函数由于某种原因失败,返回一个错误的值。 例如,如果你写一个函数从文件读取一行并返回行上的字符数。 函数的一个常见用法可能是这样的:
while($c = characters_in_line($file)){ ... };
请注意,如果特定行上的字符数为0,则while循环将在文件结束之前结束。 所以characters_in_line函数应该是特殊情况下的0个字符,而不是返回0而是true 。 这样,函数将在while循环中按预期工作,但是如果它被用作数字,也会返回正确的答案。
请注意,这不是该语言的内置部分。 而是利用Perl将string解释为数字的能力。 所以有时使用其他的蜇伤。 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=464548find。;
“0但是真”的另一个例子:
DBI模块使用“0E0”作为不影响任何logging的UPDATE或DELETE查询的返回值。 它在布尔上下文(表示查询已正确执行)中计算为true,并在数值上下文中表示查询没有更改任何logging。
我刚刚发现证据表明,string“0但是真正的”是在解释器中内置的,就像这里已经有人回答:
$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true Perl_sv_true %-p did not return a true value 0 but true 0 but true
“0但是真”是一个string,就像任何其他string一样,但是因为perl的语法,它可以起到有用的作用,即从函数返回整数零,而不会导致结果为“伪”(在perl的眼中)。
而string不一定是“0但是是真的”。 布尔意义上的“0但是假”仍然是“真”的。
考虑:
if(x) for x: yields: 1 -> true 0 -> false -1 -> true "true" -> true "false" -> true "0 but true" -> true int("0 but true") ->false
所有这一切的结果是你可以有:
sub find_x()
并且这个代码能够输出“0”作为它的输出:
if($x = find_x) { print int($x) . "\n"; }
当你想写一个函数返回一个整数值,或者false或undef (即错误的情况下),那么你必须注意零值。 返回它是错误的,不应该指出错误条件,所以返回“0但是真”使得函数返回值为真,同时在math完成时仍然返回值零。
string“0但是真”仍然是一个特例:
for arg in "'0 but true'" "1.0*('0 but true')" \ "1.0*('0 but false')" 0 1 "''" "0.0" \ "'false'" "'Ja'" "'Nein'" "'Oui'" \ "'Non'" "'Yes'" "'No'" ;do printf "%-32s: %s\n" "$arg" "$( perl -we ' my $ans=eval $ARGV[0]; $ans=~s/^(Non?|Nein)$//; if ($ans) { printf "true: |%s|\n",$ans } else { printf "false: |%s|", $ans };' "$arg" )" done
给出以下内容:(注意“警告”!)
'0 but true' : true: |0 but true| 1.0*('0 but true') : false: |0| Argument "0 but false" isn't numeric in multiplication (*) at (eval 1) line 1. 1.0*('0 but false') : false: |0| 0 : false: |0| 1 : true: |1| '' : false: || 0.0 : false: |0| 'false' : true: |false| 'Ja' : true: |Ja| 'Nein' : false: || 'Oui' : true: |Oui| 'Non' : false: || 'Yes' : true: |Yes| 'No' : false: ||
…不要忘了RTFM!
man -P'less +"/0 but [az]*"' perlfunc ... "fcntl". Like "ioctl", it maps a 0 return from the system call into "0 but true" in Perl. This string is true in boolean context and 0 in numeric context. It is also exempt from the normal -w warnings on improper numeric conversions. ...