在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"; } 

当你想写一个函数返回一个整数值,或者falseundef (即错误的情况下),那么你必须注意零值。 返回它是错误的,不应该指出错误条件,所以返回“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. ...