我该如何在Perl中使用布尔变量?

243

我已经尝试过:

$var = false;
$var = FALSE;
$var = False;

这些都不起作用。我收到了错误消息

在启用 "strict subs" 时,不允许使用裸字 "false"

42
你可能想从我的书《学习Perl》开始。它比猜测该怎么做直到你做对(猴子、打字机和《哈姆雷特》之类的)要容易得多。 :) - brian d foy
十多年后,Perl 通过新的 builtin package 获得了“真”和“假”“区分布尔值”。 - undefined
10个回答

304
在《man perlsyn》中,关于“真实和虚假”的解释如下:

数字0,字符串'0'和"",空列表"()"以及"undef"在布尔上下文中都是假的。其他所有值都是真的。

在Perl中,以下情况在条件语句中被判断为假:

0
'0'
undef
''  # Empty scalar
()  # Empty list
('')

其余的都是真的。没有裸字来表示truefalse。(注意:Perl v5.38通过新的builtin编译指示引入了truefalse)。

11
问题1:一个空列表不是假的,因为无法判断列表是真还是假。在标量上下文中,空列表返回 undef - ikegami
5
问题2:('')''是相同的值。我认为你想暗示一个由空字符串组成的元素列表(尽管圆括号不创建列表),但正如我已经提到的,无法检查列表是真还是假。 - ikegami
6
问题3:具有重载布尔运算符的对象也可以为false。 - ikegami
16
@eternicode,Perl在需要返回真和假的情况下确实有两个特定值,因此它不仅具有布尔值,还具有true(!0PL_sv_yes)和false(!1PL_sv_no)。您是说,当测试真值时,除这两个值之外的任何值都应该引发Perl错误吗?那将非常糟糕。例如:它将阻止$x ||= $default;的执行。 - ikegami
2
虽然我经常学习Perl或在不同的编程语言之间切换,但是Perl中应该有关键字true和false。没有这些关键字只会增加混淆。我知道有这个http://search.cpan.org/dist/Keyword-Boolean-0.001/lib/Keyword/Boolean.pm,但我太懒了,不想安装它。顺便抱怨一下,能不能像其他语言一样,在单行上使用"elseif"、"if语句"而不必使用大括号等等! - Matthew Lock
显示剩余14条评论

77
自5.36版本开始,您可以使用builtin模块/命名空间中的truefalse。这些是特殊的true和false值,可以使用is_bool进行识别。目前,这是一个实验性的功能。
但是,虽然可以说它们返回了真和假,但它们只是一个真或假的值。实际上,每个标量值都可以是真或假。
我遇到的关于“假值”的最完整、简洁的定义是:
引用:

任何转化为空字符串或字符串0的内容都是假值。其他所有内容都是真值。

因此,以下值都是假值:
  • 空字符串。
  • 字符串0
  • 带有零值的有符号整数。
  • 带有零值的无符号整数。
  • 带有正零值的浮点数。
  • 带有负零值的浮点数。
  • 未定义的值。
  • 具有重载布尔运算符的对象,其计算结果为上述之一。
  • 在获取时计算为上述之一的神奇变量。

任何其他标量值都为真。


关于“真零”的说明
虽然将数字转化为字符串后为0的是假的,但将字符串转化为数字后为零的不一定是假的。唯一的假字符串是0和空字符串。其他任何字符串,即使转化为数字后为零,也是真的。
以下是作为布尔值为真,作为数字为零的字符串:
  • 没有警告:
    • "0.0"
    • "0E0"
    • "00"
    • "+0"
    • "-0"
    • " 0"
    • "0\n"
    • ".0"
    • "0."
    • "0 but true"
    • "\t00"
    • "\n0e1"
    • "+0.e-9"
  • 有警告:
    • 任何Scalar::Util::looks_like_number返回false的字符串。(例如:"abc"

如果我理解正确,While numbers that stringify to 0 are true 中的单词 true 应该是 false 或者(为了避免混淆)评估为 false - Dmitry Koroliov
2
你的“简洁”定义与你更长的解释不一致。请考虑以下代码:my $value = do { package XXX; use overload q[""] => sub { "XXX" }, q[bool] => sub { 0 }; bless [] };。现在,$value将被字符串化为“XXX”,但布尔值为false。 - tobyink
1
@tobyink,简洁版本并不完美,只是我找到的最好的版本。它旨在实用,而不是全面。请注意,您的 bool 返回值会被字符串化为 0。此外,不建议创建不一致的重载,并且您返回的值可能被视为这种情况。(例如,&& 可以优化为 ||,因此如果这些不一致,您将遇到问题。) - ikegami
我不确定这里是否包含了 0x00 - Zaid
1
@Grinn,在标量上下文中的列表赋值会评估其 RHS 评估为标量的数量。(有关详细信息,请参见标量 vs 列表赋值运算符。)如果子程序没有返回任何内容,则赋值将评估为 0,即为假。如果子程序返回至少一个标量,则赋值将评估为正数,即为真。 - ikegami
显示剩余4条评论

63

Perl没有本地支持布尔类型,但您可以使用整数或字符串的比较来获得相同的行为。 Alan 的示例是使用整数比较的一种不错的方式。这里是一个例子。

my $boolean = 0;
if ( $boolean ) {
    print "$boolean evaluates to true\n";
} else {
    print "$boolean evaluates to false\n";
}

我在一些程序中做过的一件事是使用常量添加相同的行为:

#!/usr/bin/perl

use strict;
use warnings;

use constant false => 0;
use constant true  => 1;

my $val1 = true;
my $val2 = false;

print $val1, " && ", $val2;
if ( $val1 && $val2 ) {
    print " evaluates to true.\n";
} else {
    print " evaluates to false.\n";
}

print $val1, " || ", $val2;
if ( $val1 || $val2 ) {
    print " evaluates to true.\n";
} else {
    print " evaluates to false.\n";
}

"use constant" 中标记的这行代码定义了一个名为 true 的常量,它总是评估为 1,以及一个名为 false 的常量,它总是评估为 0。由于 Perl 中常量的定义方式,以下代码也会失败:

true = 0;
true = false;

错误信息应该说“无法在标量赋值中修改常量”之类的内容。

我看到您在其中一条评论中提到了字符串比较。您应该知道,由于Perl将字符串和数字类型合并在标量变量中,因此您需使用不同的语法来比较字符串和数字:

my $var1 = "5.0";
my $var2 = "5";

print "using operator eq\n";
if ( $var1 eq $var2 ) {
    print "$var1 and $var2 are equal!\n";
} else {
    print "$var1 and $var2 are not equal!\n";
}

print "using operator ==\n";
if ( $var1 == $var2 ) {
    print "$var1 and $var2 are equal!\n";
} else {
    print "$var1 and $var2 are not equal!\n";
}
这些运算符之间的差异在Perl中是非常容易引起混淆的。

6
使用use warnings;代替#! perl -w - Brad Gilbert
11
将常量用作类似宏的方式是危险的。这些代码示例并不等同于:if ($exitstatus) { exit; }if ($exitstatus == true) { exit; },这对于一个普通观察者可能并不明显。(是的,最后一个例子是糟糕的编程风格,但那不是重点)。 - Zano

16

我的最爱一直是

use constant FALSE => 1==0;
use constant TRUE => not FALSE;

这是完全独立于内部表述的。


6
太棒了!你独自修复了 Perl 编程语言! - Nostalg.io

16

我建议使用use boolean;。不过你需要从cpan安装boolean模块。


8
在Perl中,就像在生活中一样,存在许多真理。缺乏经验的人喜欢写一些傻傻的东西,比如if ($my_true_value == true)。假装有一个唯一的真理是我经验中的一条痛苦之路,也是编写低效代码的路径。请记得保持原文的意思,使翻译内容通俗易懂。 - tjd
2
Perl 的本质是哲学性的。 - ILMostro_7

9

我发现了一个tutorial,它很好地解释了Perl中哪些值为真,哪些值为假。它说明:

以下标量值被认为是假的:

  • undef - 未定义的值
  • 0 数字0,即使你将其写成000或0.0
  • '' 空字符串。
  • '0' 只包含单个0数字的字符串。

所有其他标量值,包括以下内容都为真:

  • 1 任何非0数字
  • ' ' 带有空格的字符串
  • '00' 字符串中两个或更多的0字符
  • "0\n" 0后面跟着一个换行符
  • 'true'
  • 'false' 是的,甚至字符串'false'也会被视为真。

还有一篇很好的教程,讲解了关于Perl真和假的内容。


7

(快速参考指南)True or False? 中,bobf给出了关于布尔值的精彩解释:

不同值的真实性测试:

                       Result of the expression when $var is:

Expression          | 1      | '0.0'  | a string | 0     | empty str | undef
--------------------+--------+--------+----------+-------+-----------+-------
if( $var )          | true   | true   | true     | false | false     | false
if( defined $var )  | true   | true   | true     | true  | true      | false
if( $var eq '' )    | false  | false  | false    | false | true      | true
if( $var == 0 )     | false  | true   | true     | true  | true      | true

1
虽然回答不够好,但perlmonks.org是一个强大、有声望的来源。希望能提供一些真正的内容,而不仅仅是评论和链接。 :-/ - ILMostro_7

1

使用以下文件前缀,将其添加到您的Perl脚本中,它将添加eTRUE和eFALSE,实际上将是真和假(就像Java一样)

#!/usr/bin/perl
use strict;
use warnings;

use constant { #real true false, compatible with encode_json decode_json for later (we don't want field:false... will be field:0...)
                eTRUE  =>  bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
                eFALSE =>  bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' )
             };

实际上,你应该使用它的原因很少。

我的理由是,在处理JSON时,我将0和1作为键的值,但这个技巧可以确保正确的值沿着你的脚本保持一致。


1
Perl v5.38 通过新的 builtin pragma 引入了实验性的“distinguished booleans”。这意味着现在你可以拥有你想要的 truefalse
use v5.38;
use experimental qw(builtin);
use builtin qw(true false);

my $var = false;

-3
在Raku中(曾被称为Perl_6的编程语言)的布尔值:
~$ raku
Welcome to ™ v2021.06.
Implementing the ™ programming language v6.d.
Built on MoarVM version 2021.06.

To exit type 'exit' or '^D'

> my $var = False;
False
> say $var;
False

> say $var.^name
Bool
> say $var.WHAT
(Bool)

> say ++$var
True
> say --$var
False

> say $var.Int
0
> say $var.Int + 1
1
> say ($var.Int + 1).Bool
True
> say $var.Int - 1
-1
> say ($var.Int - 1).Bool
True

> say $var.succ
True
> say $var.Int.succ
1
> say $var.pred
False
> say $var.Int.pred
-1

> say ++($var.Int); #ERROR
Cannot resolve caller prefix:<++>(Int:D); the following candidates
match the type but require mutable arguments:
    (Mu:D $a is rw)
    (Int:D $a is rw --> Int:D)
    #<SNIP>    
> say --($var.Int); #ERROR
Cannot resolve caller prefix:<-->(Int:D); the following candidates
match the type but require mutable arguments:
    (Mu:D $a is rw)
    (Int:D $a is rw --> Int:D)
    #<SNIP>

> exit

https://docs.raku.org/type/Bool
https://docs.raku.org/language/syntax#index-entry-Boolean_(literals)


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