在标量(布尔)上下文中计算表达式时,如果表达式求值为true,则Perl使用显式值1
,如果表达式求值为false,则使用空字符串。
我很好奇为什么Perl使用空字符串来表示布尔值false而不是0
这似乎更直观。
请注意,我并不关心Perl在标量(布尔)上下文中将空字符串视为false。
修改
如何使用true的字符串(例如"false"
)作为false值的字符串表示来改变现有代码的含义?我们可以说在这样的改变之后改变语义的代码不像它本来那样健壮/正确吗?我认为字符串上下文在Perl中是如此普遍,以至于导致理智语义的唯一选择是,如果布尔值在循环跳转到字符串之后保留其值...
答案 0 :(得分: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;
输出:
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
对于那些不熟悉Perl 5内部的人来说,PVNV
是一个标量结构,它包含所有三种简单标量类型(整数IV
,双精度浮点NV
和字符串{ {1}})。标志PV
,IOK
和NOK
表示整数,双精度值和字符串值都是同步的(对于某些同步定义),因此可以使用其中任何一个(即如果将其用作整数,双精度或字符串,则不需要进行转换。)
我假设为假字符串选择了空字符串,因为它更小而且更符合假字符串而不是POK
的想法。忽略我关于它变小的陈述,"0"
和""
都是相同的大小:十六个字符。它在转储中说得很对。 Perl 5为字符串增加了额外的空间,使它们能够快速增长。
哦,我讨厌你。在研究这个问题时,我发现我已经在perlopquick
撒谎,现在必须找到解决问题的方法。如果只有你像其他所有的羊一样,只是接受了Perl 5的表面怪异作为事实,那么我的工作就更少了。
编辑部分中的问题答案:
如何使用true为true的字符串(例如“false”)作为false值的字符串表示会改变现有代码的含义?
关于PL_sv_yes和PL_sv_no(比较运算符返回的规范真值和假值)的唯一特殊之处在于它们是只读的,由"1"
而不是正在运行的程序创建。如果更改它们,则不会更改真实性测试,因此设置为perl
的PL_sv_no将被视为true。您甚至可以使用"false"
的未记录功能自己执行此操作(此代码在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";
}
这是因为真实性测试首先查看字符串。
我们可以说在这样的改变之后改变语义的代码不像它本来那样健壮/正确吗?
它会被打破。即使你限制自己设置为int 0或字符串“0”(两者都是false),它也会破坏一些有效的代码。
我认为字符串上下文在Perl中是如此普遍,导致理智语义的唯一选择是,如果布尔值在循环跳转到字符串之后保留其值...
是
答案 1 :(得分:5)
您可以重载true,false和undef的字符串化,例如this:
&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'
答案 2 :(得分:2)
It's not just ""
that's false in Perl。至于为什么......它要么是因为Perl很棒还是很糟糕 - 取决于你的个人喜好:)
答案 3 :(得分:2)
数字0和空字符串最终在Perl中评估为false。我认为这是语言设计的问题。在编写自己的代码时,您当然可以假设任何一种错误的编码约定。
有关详细信息,请查看“How do I use boolean variables in Perl?”。
答案 4 :(得分:1)
以下是解决问题的方法:
my $res = ($a eq $b) *1;
*1
将($a eq $b)
得到的布尔值转换为标量。