用'||'评估语句在Perl

时间:2011-10-19 14:46:42

标签: perl

有人可以解释一下这里发生了什么吗?

我尽可能地简化了。

( 1 || 2 == 1 )     is TRUE (as expected)
( 1 || 2 == 2 )     is TRUE (as expected)

我也希望以下两者都是正确的(但这可能表明缺乏理解......)

( 1 == ( 1 || 2 ) ) is TRUE  
( 2 == ( 1 || 2 ) ) is FALSE <--- !!! I don't understand this..

现在开始有点奇怪了......

( 2 == 1 || 2 )     is TRUE  
( 3 == 1 || 2 )     is TRUE  <--- !!! I don't understand this..

经过多次演绎后,我发现以下内容:

( 1 == ( 1 || 2 ) ) is FALSE
( 2 == ( 1 || 2 ) ) is TRUE

( 1 == ( 1 && 2 ) ) is TRUE
( 2 == ( 1 && 2 ) ) is FALSE

您可能猜测我正在尝试按照以下方式执行某些操作:

sub foo {
    # ... blah blah ...
    return 0 if $status == ( 2 || 4 || 7 || 9);
    # ... do other stuff ...
    return 1;
}

my $result = foo();
if ($result) { 
    # then do something based on a result
    } else {
    # log failure or whatever
}

我知道我可以使用这个成语,但额外的“$ status”似乎是多余的:

return 0 if ( $status == 1 || $status == 4 || $status == 7 ); # and so on...

我也知道我可以使用带有替换的正则表达式或检查该值是否在允许值的数组中。

但我想明白为什么这不像我期望的那样。

7 个答案:

答案 0 :(得分:10)

$status == ( 2 || 4 || 7 || 9)

不会做你期望的。 (如果它确实按照您的预期行事,您认为$status == (2 && 4 && 7 && 9)应该是什么意思?)该陈述等同于

$status == 2

||&&二进制运算符,它们总是返回其标量操作数之一。将它们视为等效于这些二元函数可能有所帮助:

sub OR {
    my ($a,$b) = @_;
    if ($a) {
        return $a;
    } else {
        return $b;
    }
}

sub AND {
    my ($a,$b) = @_;
    if ($a) {
        return $b;
    } else {
        return $a;
    }
}

(我正在掩饰||&&的短路功能,但这对于这篇文章来说并不那么重要。)

注意==的优先级高于||&&,我们可以用ANDOR重写所有表达式:

( 1 || 2 == 1 )     -->   (OR(1,2==1))  --->  OR(1,0) --> 1  TRUE
( 1 || 2 == 2 )     -->   (OR(1,2==2))  --->  OR(1,1) --> 1  TRUE

这两个表达式都是正确的,但不是因为你期望的原因。

( 1 == ( 1 || 2 ) ) -->   (1 == OR(1,2))   --->   (1==1) TRUE
( 2 == ( 1 || 2 ) ) -->   (2 == OR(1,2))   --->   (2==1) FALSE


( 2 == 1 || 2 )     -->   OR(2==1,2)   --->  OR(0,2) -->  2  TRUE  
( 3 == 1 || 2 )     -->   OR(3==1,2)   --->  OR(0,3) -->  3  TRUE


( 1 == ( 1 || 2 ) ) -->   (1==OR(1,2)) --->  (1==1)  TRUE, not FALSE
( 2 == ( 1 || 2 ) ) -->   (2==OR(1,2)) --->  (2==1)  FALSE, not TRUE

( 1 == ( 1 && 2 ) ) -->   (1==AND(1,2)) ---> (1==1) TRUE
( 2 == ( 1 && 2 ) ) -->   (2==AND(1,2)) ---> (2==1) FALSE

您最初的检查想法

$status == ( 2 || 4 || 7 || 9)

相当于

$status == OR(OR(OR(2,4),7),9)
$status == OR(OR(2,7),9)
$status == OR(2,9)
$status == 2

答案 1 :(得分:5)

( 2 == ( 1 || 2 ) ) is FALSE <--- !!! I don't understand this..

||运算符返回它遇到的第一个“true”值或false。因此,1||2评估为1,与2的数字比较失败。至于您的代码,您可以使用Perl6::Junction

if ($status == any(1, 4, 7)) {
    ...
}

答案 2 :(得分:5)

||运算符根本无法正常工作(希望?)。你可以通过打印出一些表达式的结果来看到这一点。

$ perl -E'say 1 || 2' # 1
$ perl -E'say 2 || 1' # 2

操作员很懒惰。它只评估操作数,直到它知道结果是什么。

实现目标的两种方法。

1 /创建包含您感兴趣的值的哈希值。

my %good_status = map { $_ => 1 } qw[2 4 7 9];
return if $good_status{$status};

2 /使用List::MoreUtils中的any功能。

use List::Utils 'any';
return if any { $status == $_ } qw[2 4 7 9];

答案 3 :(得分:5)

||语句不能以您尝试使用它的方式使用。在英语中说“如果1是1或2”是有道理的,但在大多数(如果不是所有编程语言)中你必须说“如果1是1或1是2”(即1 == 1 || 1 == 2或某些宏物)。

实际发生的是||&&,当用于两个数字时,正在评估他们找到的第一个非零值。所以1 || 6 -> 1 6 || 1 -> 6。如果不涉及括号,则首先评估==,结果为:

( 1 || 2 == 1 ) -> (1) == 1 -> true
( 1 || 2 == 2 ) -> (1) == 2 -> false

( 1 == ( 1 || 2 ) ) -> 1 == (1) -> true
( 2 == ( 1 || 2 ) ) -> 2 == (1) -> false

( 2 == 1 || 2 ) -> false || 2 -> 2 -> true
( 3 == 1 || 2 ) -> false || 2 -> 2 -> true

( 1 == ( 1 || 2 ) ) -> 1 == (1) -> true
( 2 == ( 1 || 2 ) ) -> 2 == (1) -> false

( 1 == ( 1 && 2 ) ) -> 1 == (1) -> true
( 2 == ( 1 && 2 ) ) -> 2 == (1) -> false

答案 4 :(得分:4)

你已经对OR逻辑给出了解释,所以我将花费它,只是告诉你在perldoc perlop中可以找到一个优先级表。您应该能够找出具有该信息的逻辑。

您正在寻找的内容可能是switch声明的功能:

use v5.10;
sub foo {
    my $status = shift;
    given ($status) {
        when ([2,4,7,9]) { return 0 }
        default { return 1 }
    }
}

答案 5 :(得分:3)

( 2 == ( 1 || 2 ) ) is FALSE <--- !!! I don't understand this..
首先在( 1 || 2 )评估

1,然后与2 ==&gt;进行比较当然是假!!

( 3 == 1 || 2 )     is TRUE  <--- !!! I don't understand this..
首先评估

3 == 1,结果为0/false,然后|| 2返回2&lt; ==&gt;真。

return 0 if ( $status == 1 || $status == 4 || $status == 7 );

可以改写为:

return 0 if $status =~ /^[147]$/;

答案 6 :(得分:1)

你现在看到它的运算符的二元性给了他们他们的行为。更为奇怪的是量子力学世界,Quantum::Superpositions从中吸取灵感。

试试这个有趣的事情(它做的事情更接近你原来的期望):

#!/usr/bin/env perl

use strict;
use warnings;
no warnings 'qw';

use Quantum::Superpositions;

my @cases = qw'
(any(1,2)==1)
(any(1,2)==2)
(1==any(1,2))
(2==any(1,2))
(2==any(1,2))
(3==any(1,2))
(1==any(1,2))
(2==any(1,2))
(1==all(1,2))
(2==all(1,2))
';


print "$_ -> ", eval, "\n" for @cases;

当然,你可以用这些叠加状态做更奇怪的事情,比如国家的产品等等。整个事情对于一些轻读(如果你和我一样令人讨厌)都是好的。

阅读其他一些答案,这也像zoul提到的Perl6::Junctions模块