Perl函数返回布尔值时,实际上返回什么?

12
Perl的defined函数(以及许多其他函数)返回“布尔值”。
由于Perl实际上没有布尔类型(使用像1表示 true , 0 或 undef 表示 false 的值),因此Perl是否指定了返回布尔值的确切内容?例如,defined(undef) 会返回 0 还是 undef ,并且它是否会受到更改的影响?

5
附注:您可以通过双重否定将任何值转换为其对应的布尔值。这会导致 !! 伪运算符。它非常有用,可以返回通用的真值或假值,而不是一些神奇数字。 - amon
4个回答

13
几乎所有情况下(即除非有特殊原因),Perl返回两个静态分配的标量之一:&PL_sv_yes(表示真)和&PL_sv_no(表示假)。以下是它们的详细信息:
>perl -MDevel::Peek -e"Dump 1==1"
SV = PVNV(0x749be4) at 0x3180b8
  REFCNT = 2147483644
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x742dfc "1"\0
  CUR = 1
  LEN = 12

>perl -MDevel::Peek -e"Dump 1==0"
SV = PVNV(0x7e9bcc) at 0x4980a8
  REFCNT = 2147483647
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x7e3f0c ""\0
  CUR = 0
  LEN = 12

yes是一个三元变量(IOK,NOK和POK)。它包含一个带符号整数(IV),值为1,一个浮点数(NV),值为1,和一个字符串(PV),值为1。

no也是一个三元变量(IOK,NOK和POK)。它包含一个带符号整数(IV),值为0,一个浮点数(NV),值为0,和一个空字符串(PV)。这意味着它会被字符串化为空字符串,并且将其转换为数字时结果为0。它既不等于空字符串,也不等于数字0。

>perl -wE"say 0+(1==0);"
0

>perl -wE"say 0+'';"
Argument "" isn't numeric in addition (+) at -e line 1.
0

不是零 0

>perl -wE"say ''.(1==0);"


>perl -wE"say ''.0;"
0

不能保证这种情况总是不变的。也没有理由依赖这一点。如果您需要特定的值,可以使用类似以下的方法:

my $formatted = $result ? '1' : '0';

2
ikegami,您可能考虑添加一个链接到这个答案以获取更多信息 :) - Chankey Pathak
5
特殊的假值在 perlsyn 中有详细记录。虽然这并不完全保证它永远不会改变,但 Perl 5 不会没有非常充分的理由就破坏向后兼容性。 - cjm
@cjm,Aj很酷,我不知道它被记录了。这使得它非常安全。 - ikegami

6
它们返回一种特殊的假值,在字符串上下文中是"",但在数字上下文中是0(没有非数字警告)。 真值并不那么特殊,因为在任何情况下都是1。 defined()不会返回未定义值。
(您可以使用例如Scalar :: Util :: dualvar(0,“”)等创建类似的值。)

3

也许它永远不会改变,但是 Perl 并没有规定 defined(...) 返回的确切布尔值。

在使用布尔值时,良好的代码不应依赖于用于 true 和 false 的实际值。

示例:

# not so great code:
my $bool = 0;   #
...
if (some condition) {
  $bool = 1;
}

if ($bool == 1) { ... }

# better code:
my $bool;       # default value is undef which is false

$bool = some condition;

if ($bool) { ... }

99.9%的情况下,我们不需要关心布尔值所使用的值。 尽管如此,在某些情况下,最好使用明确的0或1而不是布尔值。例如:

sub foo {
    my $object = shift;
    ...
    my $bool = $object;
    ...
    return $bool;
}

意图是让foo()被调用时,传递一个引用或者undef,如果$object未定义则应该返回false。问题是,如果$object已定义,foo()将返回对象本身,从而创建另一个对该对象的引用,这可能会干扰其垃圾回收。因此,在这里最好使用显式的布尔值,即:

  my $bool = $object ? 1 : 0;

因为可能会创建对引用的不必要引用,所以请小心使用引用本身来表示其真实性(即其定义性)。

请注意,这里保留了HTML标签。

3
由于这是官方的手册,因此其确切的返回值未指定。如果Perl文档谈论布尔值,则几乎始终会在布尔上下文中评估该值:if (defined ...)或print while <>. 在这种情况下,几个值会计算为false,包括0、undef、""(空字符串),甚至等于"0"的字符串。
在布尔上下文中,所有其他值都会被计算为真,包括臭名昭著的示例"0 but true"。
由于文档过于模糊,我永远不会依赖于defined()返回未定义情况下的任何特定值。但是,如果您仅将defined()用于布尔上下文而不将其与特定值进行比较,则始终可以正常工作。
可行:print "yes\n" if defined($var)
不可移植/ 面向未来:print "yes\n" if defined($var) eq ''或类似的东西

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接