2010-10-12 81 views
16

在标量(布尔值)上下文中计算表达式时,如果表达式计算结果为真,则Perl使用显式值1,如果表达式计算结果为false,则使用空字符串。 我很好奇为什么Perl使用空字符串来表示布尔虚假值,而不是0这看起来更直观。为什么Perl使用空字符串来表示布尔值false值?

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

编辑

会如何使用字符串,它是真实的("false"例如)为假值的字符串表示改变现有代码的含义?我们可以说在这样的变化之后改变语义的代码比它本来不那么健壮/正确吗?我猜字符串上下文在Perl中非常普遍,唯一的选择导致了健全的语义,如果布尔值在向一个字符串和从一个字符串往返跳动后保留其值...

+0

可能的重复[为什么!1在Perl中什么都不给我?](http://stackoverflow.com/questions/1134962/why-does-1-give-me-nothing-in-perl) – Thilo 2016-09-06 01:21:47

回答

30

各种逻辑运算符不会返回空字符串,它们会在所有三种简单标量类型中返回假或真值。它只是看起来像它因为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和字符串PV)。标记IOK,NOKPOK表示整数,双精度和字符串值全部同步(对于同步中的某些定义),因此可以使用它们中的任何一个(即,如果使用它们,则不需要进行任何转换作为整数,双精度或字符串)。

我假定空字符串被选为虚假字符串,因为它 更小, 更符合虚假字符串的想法,而不是"0"。忽略我关于它变小的说法,"""1"都是相同的大小:16个字符。它在转储中说得很对。 Perl 5为字符串增加了额外的空间,使它们能够快速增长。

哦,我讨厌你。在研究中,我发现我在perlopquick中撒谎,现在必须找到一种解决办法。如果只有你像所有其他的羊一样,只是接受Perl 5的表面怪异,那么我的工作量就会减少。

答案在EDIT部分中的问题:

会如何使用字符串的虚假值改变现有代码的意思是真正的字符串表示(例如“假”)?

约约PL_sv_yes和PL_sv_no(由比较运算符返回的标准地真假值)唯一特殊的事情是,他们是只读的,由perl不是正在运行的程序创建的。如果你改变他们,这不会改变感实性测试,所以它被设置为一个"false"将PL_sv_no作为真正的治疗。你甚至可以自己做(此代码将停止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"; 
} 

输出

opps 

这是因为感实性测试检查在弦首先。

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

将直线上升打破。即使您限制自己将其设置为int 0或字符串“0”(两者均为false),它也会破坏一些有效的代码。

我猜字符串上下文是Perl中如此普遍,导致理智语义唯一的选择是,如果布尔值后轮跳闸,并从一个字符串保存它的价值...

是。

+9

我恨/爱你们俩 - 这个问题引起了我送docpatch现在只是P5P:perlguts误指'PL_sv_no'为'PL_sv_false'(“假”问题的标量)。 :) – hobbs 2010-10-12 12:40:42

+2

@Piotr Dobrogost看看你做了什么!看问题来自哪些问题?你正在使Perl 5更好!你怎么能和自己一起生活? – 2010-10-12 12:50:29

+0

谢谢,应用,hobbs。 :-) – rafl 2010-10-12 12:55:00

2

It's not just"" that's false in Perl。至于为什么...这是因为Perl是真棒或可怕的 - 取决于你的个人喜好:)

+1

Perl是在RSA加密之前和之后唯一可以读取的语言。 – TBH 2010-10-12 13:02:15

+2

@TBH不,APL是。 Perl以未加密的形式可读性略高。 – 2010-10-12 13:44:01

+2

@Chas - 我想你的意思是说“加密形式”。 – DVK 2010-10-12 14:13:23

2

数字0和空字符串最终在Perl中评估为false。我认为这是语言设计的问题。在编写自己的代码时,你当然可以假定任何一种错误的编码约定。

有关更多详情,请查看“How do I use boolean variables in Perl?”。

5

可以重载的真,假和民主基金,像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' 
+0

非常好的定制。我不知道Perl允许这样的事情。 – 2010-10-12 18:52:39

+3

非常错误。 +1。 – rafl 2010-10-13 02:32:28

+0

Internals'软件包及其中的函数或变量不用于公共使用(因此名称)。在全球范围内改变运营商返回的真实价值和虚假价值是不可取的。绕过'Svreadonly'的原型只是锦上添花。这就是说,漂亮。 – 2010-10-13 16:21:11

1

这里是我解决该问题如何得到:

my $res = ($a eq $b) *1; 

*1将从($a eq $b)造成布尔成标量。

相关问题