Тернарный оператор в perl дает неожиданный результат при назначении переменной в операторе - PullRequest
0 голосов
/ 02 июня 2011

Я пытаюсь сделать переход с 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);

в чем здесь разница?!

Ответы [ 6 ]

11 голосов
/ 02 июня 2011

Это связано с приоритетом оператора Perl.В Perl

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

- это то же самое, что и

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

, обратите внимание, что пара связывается с FRONT.

, и это приводит к еще одной запутанной особенности Perl: условные lvalues: Вы можете сделать это (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)

4 голосов
/ 02 июня 2011

Ах, вы поняли, почему ?: плохая идея, за исключением тривиальных случаев.

Проблема с приоритетом оператора.Скорее всего, вы захотите сделать это:

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

Однако с вашим кодом есть несколько других проблем.

  • Вы должны объявить свои переменные.Они не объявляются при первом использовании, как в PHP;Вы делаете это явно с помощью оператора my.
  • Вы должны всегда, всегда, всегда use strict и use warnings в Perl-коде.Эти прагмы отключают древние махинации Perl и предупреждают о подозрительных операциях, которые могут быть ошибками.
  • Первая строка функции обычно должна распаковывать @_;есть очень мало причин использовать $_[0] непосредственно в функции.(И это опасно, так как @_ является псевдонимом; вы можете изменить переменные вызывающего!)

Так что вы, вероятно, захотите что-то похожее на это:

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 .

1 голос
/ 02 июня 2011

Это приоритетная вещь.

($_[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";
1 голос
/ 02 июня 2011

Если вы напишите:

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

тогда вы получите ожидаемый результат.

0 голосов
/ 02 июня 2011

В основном, приоритет оператора.

0 голосов
/ 02 июня 2011

Я считаю, $return; - синтаксическая ошибка. Вам не нужно объявлять это - переменные в perl и php не имеют смысла.
Кроме того, = имеет приоритет над ?:, поэтому вам необходимо добавить () к обоим назначениям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...