为什么Perl使用空字符串来表示布尔值false?

Pio*_*ost 18 perl boolean boolean-expression

在标量(布尔)上下文中1计算表达式时,如果表达式求值为true ,则Perl使用显式值作为结果;如果表达式求值为false,则使用空字符串.我很好奇为什么Perl使用空字符串来表示布尔值false而不是0更直观.

请注意,我并不关心Perl将空字符串视为标量(布尔)上下文中的false.

编辑

如何使用true("false"例如)字符串作为false值的字符串表示来改变现有代码的含义?我们可以说在这样的改变之后改变语义的代码不像它本来那样健壮/正确吗?我猜字符串上下文在Perl中是如此普遍,以至于导致理智语义的唯一选择是,如果布尔值在向字符串转换为字符串之后保留其值...

Cha*_*ens 32

各种逻辑运算符不返回空字符串,它们在所有三种简单标量类型中返回false或true值.它看起来像是返回一个空字符串,因为print它的参数强制一个字符串上下文:

#!/usr/bin/perl

use strict;
use warnings;

use Devel::Peek;

my $t = 5 > 4;
my $f = 5 < 4;

Dump $t;
Dump $f;
Run Code Online (Sandbox Code Playgroud)

输出:

SV = PVNV(0x100802c20) at 0x100827348
  REFCNT = 1
  FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x100201e60 "1"\0
  CUR = 1
  LEN = 16
SV = PVNV(0x100802c40) at 0x100827360
  REFCNT = 1
  FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x100208ca0 ""\0
  CUR = 0
  LEN = 16
Run Code Online (Sandbox Code Playgroud)

对于那些不熟悉Perl 5内部的人来说,a PVNV是一个标量结构,它包含所有三种简单的标量类型(整数IV,双精度浮点数NV和字符串PV).标志IOK,NOK并且POK表示整数,双精度和字符串值都是同步的(对于某些同步定义),因此可以使用它们中的任何一个(即,如果将它用作整数,则不需要进行转换,double或string).

我假设为假字符串选择了空字符串,因为它更小并且更符合假字符串的想法"0".忽略我的发言以为这是小,都"""1"大小都一样:十六个字符.它在转储中说得很对.Perl 5为字符串增加了额外的空间,使它们能够快速增长.

哦,我讨厌你.在研究这个问题时,我发现我已经撒谎,perlopquick现在必须找到解决问题的方法.如果只有你像其他所有的羊一样,只是接受了Perl 5的表面怪异作为事实,那么我的工作就会减少.

编辑部分中的问题答案:

如何使用true的字符串(例如"false")作为false值的字符串表示会改变现有代码的含义?

关于PL_sv_yes和PL_sv_no(比较运算符返回的规范真值和假值)的唯一特殊之处在于它们是只读的,并且perl不是由正在运行的程序创建的.如果更改它们,它不会更改真实性测试,因此设置为的PL_sv_no "false"将被视为true.您甚至可以使用以下未记录的功能自行执行此操作(此代码在Perl 5.18和最新的Perl之间的某个位置停止工作)perl:

#!/usr/bin/perl

use strict;
use warnings;
use Scalar::Util qw/dualvar/;

BEGIN {
        # use the undocumented SvREADONLY function from Internals to
        # modify a reference to PL_sv_no's readonly flag
        # note the use of & to make the compiler not use SvREADONLY's
        # prototype, yet another reason prototypes are bad and shouldn't
        # be used
        &Internals::SvREADONLY(\!!0, 0);

        # set PL_sv_no to a dualvar containing 0 and "false"
        ${\!!0} = dualvar 0, "false";
}

if (5 < 4) {
        print "oops\n";
}
Run Code Online (Sandbox Code Playgroud)

输出

opps
Run Code Online (Sandbox Code Playgroud)

这是因为真实性测试首先查看字符串.

我们可以说在这样的改变之后改变语义的代码不像它本来那样健壮/正确吗?

它会被直接打破.即使你限制自己设置为int 0或字符串"0"(两者都是false),它也会破坏一些有效的代码.

我猜字符串上下文在Perl中是如此普遍,以至于导致理智语义的唯一选择是,如果布尔值在向字符串转换为字符串之后保留其值...

是.

  • 我讨厌/爱你们两个 - 这个问题导致我刚刚向p5p发送了一个docpatch:perlguts错误地将`PL_sv_no`(所谓的"假"标量)称为"PL_sv_false".:) (9认同)
  • @Piotr Dobrogost看看你做了什么!看看提问的内容是什么?你在Perl 5中制作的东西更好!你怎么能和自己一起生活? (2认同)
  • @Piotr Dobrogost [`perldoc perlguts`](http://perldoc.perl.org/perlguts.html)文档错误地声明有一个`PL_sv_false` C函数返回与`1 <0`相同的值.该函数实际上名为`PL_sv_no`.有关更多信息,请阅读[p5p post](http://www.nntp.perl.org/group/perl.perl5.porters/2010/10/msg164959.html). (2认同)

MkV*_*MkV 5

你可以重载true,false和undef的字符串化,如下所示:

&Internals::SvREADONLY( \ !!1, 0);    # make !!1 writable
${ \ !!1 } = 'true';                  # change the string value of true
&Internals::SvREADONLY( \ !!1, 1);    # make !!1 readonly again
print 42 == (6*7);                    # prints 'true'

&Internals::SvREADONLY( \ !!0, 0);    # make !!0 writable
${ \ !!0 } = 'false';                 # change the string value of false
&Internals::SvREADONLY( \ !!0, 1);    # make !!0 readonly again
print 42 == (6*6);                    # prints 'false'
Run Code Online (Sandbox Code Playgroud)