Atribuição dentro de problemas de operadores condicionais ternários Perl
-
08-06-2019 - |
Pergunta
Este trecho de código Perl no meu programa está dando o resultado errado.
$condition ? $a = 2 : $a = 3 ;
print $a;
Não importa qual seja o valor $condition
é, a saída é sempre 3, como assim?
Solução
Isso é explicado no Perl documentação.
Devido à precedência do operador Perl, a instrução está sendo analisada como
($condition ? $a= 2 : $a ) = 3 ;
Porque o ?:operador produz um resultado atribuível, 3 é atribuído ao resultado da condição.
Quando $condição é verdadeira, isso significa ($a=2)=3 dando $a=3
Quando $condição é falsa, isso significa ($a)=3 dando $a=3
A maneira correta de escrever isso é
$a = ( $condition ? 2 : 3 );
print $a;
Fomos afetados por isso no trabalho, por isso estou postando aqui esperando que outros considerem isso útil.
Outras dicas
Assim que você tiver a ideia de que pode estar sofrendo de problemas de precedência, um truque para descobrir o que Perl achou que você quis dizer:
perl -MO=Deparse,-p -e '$condition ? $a= 2 : $a= 3 ; print $a;'
No seu caso, isso mostrará:
(($condition ? ($a = 2) : $a) = 3);
print($a);
-e syntax OK
... nesse ponto você deveria estar dizendo "ah, isso explica tudo"!
Apenas para estender a resposta anterior ...Se, por qualquer motivo, as atribuições precisarem fazer parte da condicional, você desejaria escrevê-las assim:
$condition ? ($a=2) : ($a=3);
Isso seria útil se você estivesse atribuindo variáveis diferentes com base na condição.
$condition ? ($a=2) : ($b=3);
E se você estiver escolhendo a variável, mas atribuindo a mesma coisa de qualquer maneira, você pode até fazer isso:
($condition ? $a : $b) = 3;
Devido à precedência do operador Perl, a instrução está sendo analisada como:
($condition ? $a = 2 : $a ) = 3 ;
Porque o ?:operador produz um resultado atribuível, 3 é atribuído ao resultado da condição.
Quando $condição é verdadeira, isso significa $a=2=3 dando $a=3
Quando $condição é falsa, isso significa $a=3 dando $a=3
A maneira correta de escrever isso é
$a = $condition ? 2 : 3;
Em geral, você realmente deve abandonar o hábito de usar condicionais para fazer atribuições, como no exemplo original - é o tipo de coisa que faz com que o Perl ganhe a reputação de ser somente gravação.
Uma boa regra é que as condicionais são apenas para valores simples, nunca para expressões com efeitos colaterais.Quando você ou outra pessoa precisar ler este código daqui a oito meses, você preferiria que fosse lido assim?
$x < 3 ? foo($x) : bar($y);
Ou assim?
if ($x < 3) {
$foo($x);
} else {
$bar($y);
}
Uma sugestão para a resposta do Tithonium acima:
Se você deseja atribuir valores diferentes à mesma variável, isso pode ser melhor (do jeito do copybook):
$a = ($condição)?2:3;