当在语句中分配变量时,perl中的三元运算符会产生意外结果


Ternary operator in perl yields unexpected result when assigning a variable in the statement

我正试图从php过渡到perl,预计会遇到一些奇怪的情况。我无法理解为什么我的代码的一个版本与另一个版本相比有效。

此操作失败:

sub tester
{
$return;
($_[0] < 10) ? $return = "youre a youngin" : $return = "youre an old person";
return $return;
}

print "how old are you?";
$a = <>;
chomp $a;
print  tester($a);  #both result in "youre an old person"

然而,这个是有效的:

sub tester
{
    return ($_[0] < 10) ? "youre a youngin" : "youre an old person";
}

print "how old are you?";
$a = <>;
chomp $a;
print  tester($a);

这里真正的区别是什么?!

它与Perl的运算符优先级有关。在Perl中,

($_[0] < 10) ? $return = "youre a youngin" : $return = "youre an old fart";

与相同

( ($_[0] < 10) ? $return = "youre a youngin" : $return ) = "youre an old fart";

注意paren绑定到FRONT。

这导致了Perl的另一个令人困惑的特性:条件左值:你可以这样做(CONDITION ? $ASSIGN_A_IF_CONDITION_IS_TRUE : $ASSIGN_B_IF_CONDITION_IS_FALSE) = 2

这是一个修复

($_[0] < 10) ? ($return = "youre a youngin") : ($return = "youre an old fart");

http://codepad.org/MxBAy7wy

编辑:

然而,大多数人会写

$return = ($_[0] < 10) ? "youre a youngin" : "youre an old fart";

,保存了两次键入变量的冗余。

根据Perl和PHP文档,Perl ?:是右关联的,PHP ?:是左关联的。(http://perldoc.perl.org/perlop.html)(http://php.net/manual/en/language.operators.precedence.php)

啊,您已经发现了为什么?:除了在琐碎的情况下是个坏主意。

运算符优先级是个问题。你很可能想这样做:

$return = ($_[0] < 10) ? "you're a youngin'" : "you're an old fart";

不过,您的代码还有一些其他问题。

  • 您应该声明您的变量。它们并没有像在PHP中那样在首次使用时声明;您可以使用my运算符显式执行此操作
  • 您应该在Perl代码中始终始终use strictuse warnings。这些实用程序禁用了古老的Perl恶作剧,并警告可能是错误的可疑操作
  • 函数的第一行通常应该是拆包@_;几乎没有理由在函数中直接使用CCD_ 9。(这样做很危险,因为@_是别名;您可以更改调用者的变量!)

所以你可能想要更像这样的东西:

use strict;
use warnings;
sub tester {
    my ($age) = @_;
    if ($age < 10) {
        return "you're a youngin'";
    }
    else {
        return "you're an old fart";
    }
}
print "how old are you? ";
my $age = <>;
chomp $age;
print tester($age);

请注意,my $x = ...声明一个变量并分配一个值,而my ($x, $y, $z) = ...声明多个变量并将列表拆包到其中。

my变量被称为词法变量,并且只存在于声明它们的块中;它们不像PHP变量那样具有函数范围。事实上,你可能应该在perlsub上读到它们。

这是一个优先事项。

($_[0] < 10) ? ($return = "youre a youngin") : ($return = "youre an old fart");

效果更好。

但老实说,没有一个认真的Perl程序员会这样写。首先,他们会将以下内容放在程序的首位:

use warnings;
use strict;

其次,他们会把争论放在一个地方:

sub tester {
    my $arg = shift;

第三,他们将以两种方式之一编写条件:

if ($arg < 10) {
    $return = "you're a youngin";
}
else {
    $return = "you're an old fart";
}

如果他们来自Lisp背景,他们可能会省去$return变量,只写:

return $arg < 10 ? "you're a youngin" : "you're an old fart";

如果您编写:

sub tester
{
   return ($_[0] < 10) ? "You're a young'un" : "You're an oldie";
}

然后你就会得到你期望的结果。

基本上,运算符优先级。

我认为$return;是一个语法错误。您不需要声明它——perl和php中的变量是无作用域的
此外,=优先于?:,因此需要将()添加到这两个分配中。