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

发布于 2024-09-27 02:16:38 字数 385 浏览 3 评论 0原文

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

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

编辑

使用 true 字符串(例如 "false")作为 false 值的字符串表示将如何改变现有代码的含义?我们是否可以说,在进行此类更改后更改语义的代码不如其应有的那样健壮/正确?我猜字符串上下文在 Perl 中是如此普遍,以至于导致理智语义的唯一选择是布尔值在往返于字符串之后是否保留其值......

When evaluating an expression in a scalar (boolean) context, Perl uses the explicit value 1 as a result if the expression evaluates to true and the empty string if the expression evaluates to false.
I'm curious why Perl uses the empty string to represent boolean false value and not 0 which seems more intuitive.

Note that I'm not concerned with Perl treating the empty string as a false in scalar (boolean) context.

EDIT

How would using string which is true ("false" for instance) as a string representation of false values change the meaning of existing code? Could we say that code that changes semantics after such a change is less robust/correct than it could have been? I guess string context is so pervasive in Perl that the only option leading to sane semantics is if boolean value preserve its value after round tripping to and from a string...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

遗心遗梦遗幸福 2024-10-04 02:16:38

各种逻辑运算符不返回空字符串,它们在所有三种简单标量类型中返回 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 和字符串 PV)的结构。标志 IOKNOKPOK 表示整数、双精度和字符串值全部同步(对于同步的某些定义) )因此可以使用其中任何一个(即,如果将其用作整数、双精度或字符串,则无需进行转换)。

我假设选择空字符串作为假字符串,因为它更小并且“0”更符合假字符串的概念。忽略我关于它更小的说法,"""1" 大小相同:十六个字符。垃圾场里就是这么说的。 Perl 5 为字符串添加了额外的空间,以允许它们快速增长。

哦,我恨你。在研究这个问题时,我发现我在 perlopquick 中撒了谎,现在将必须找到一种方法来解决它。如果您像所有其他绵羊一样并且接受 Perl 5 表面上的怪异作为事实,那么我要做的工作就会更少。

编辑部分问题的答案:

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

PL_sv_yes 和 PL_sv_no(比较运算符返回的规范 true 和 false 值)的唯一特殊之处在于它们是只读的,并且是由 perl 创建的,而不是由正在运行的程序创建的。如果更改它们,不会更改真实性测试,因此设置为 "false" 的 PL_sv_no 将被视为 true。您甚至可以使用 perl 未记录的功能自行执行此操作(此代码在 Perl 5.18 和最新 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 中是如此普遍,以至于导致理智语义的唯一选择是布尔值在与字符串往返之后是否保留其值......

是的。

The various logical operators don't return an empty string, they return a false or true value in all three simple scalar types. It just looks like it returns an empty string because print forces a string context on its arguments:

#!/usr/bin/perl

use strict;
use warnings;

use Devel::Peek;

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

Dump $t;
Dump $f;

Output:

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

For those not familiar with the Perl 5 internals, a PVNV is a scalar structure that holds all three simple scalar types (integer IV, double precision float NV, and string PV). The flags IOK, NOK, and POK mean that the integer, double, and string values are all in sync (for some definition of in sync) so any one of them may be used (i.e. no conversions need to take place if you use it as an integer, double, or string).

I assume the empty string was chosen for the false string because it is smaller and is more in keeping with the idea of a false string than "0". Ignore my statement about it being smaller, both "" and "1" are the same size: sixteen characters. It says so right in the dump. Perl 5 adds extra space to strings to allow them to grow quickly.

Oh, and I hate you. In researching this I have found that I have lied in perlopquick and will now have to find a way to fix it. If only you had been like all of the other sheep and just accepted Perl 5's surface weirdness as fact, I would have less work to do.

Answers to the questions in the EDIT section:

How would using string which is true ("false" for instance) as a string representation of false values change the meaning of existing code?

The only special things about about PL_sv_yes and PL_sv_no (the canonically true and false values returned by comparison operators) are that they are read only and are created by perl not the program that is running. If you change them, it does not change the truthiness test, so a PL_sv_no that is set to "false" will be treated as true. You can even do this yourself (this code stops working at some point between Perl 5.18 and the latest Perl) using undocumented features of 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";
}

outputs

opps

This is because the truthiness test looks at strings first.

Could we say that code that changes semantics after such a change is less robust/correct than it could have been?

It will be straight up broken. Even if you restrict yourself to setting it to an int 0 or a string "0" (both of which are false), it will break some valid code.

I guess string context is so pervasive in Perl that the only option leading to sane semantics is if boolean value preserve its value after round tripping to and from a string...

Yes.

情痴 2024-10-04 02:16:38

您可以重载 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'

You can overload the stringification of true, false and undef, like 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'
逆光下的微笑 2024-10-04 02:16:38

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

有关更多详细信息,请查看“如何在 Perl 中使用布尔变量? ”。

Both number 0 and empty string ultimately evaluate as false in Perl. I think this is a matter of language design. When writing your own code, you can of course assume any which one false encoding convention.

For further details, check out "How do I use boolean variables in Perl?".

怪异←思 2024-10-04 02:16:38

以下是我解决该问题的方法:

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

*1($a eq $b) 生成的布尔值转换为标量。

Here is how I got around the problem:

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

The *1 converts the boolean resulting from ($a eq $b) into a scalar.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文