web-dev-qa-db-fra.com

Affectation à l'aide de l'opérateur ternaire?

Je suis sur Perl 5.8 et j'ai besoin d'attribuer une valeur par défaut. J'ai fini par faire ça:

if ($model->test) {
    $review = "1"
} else {
    $review = ''
}

La valeur de $model->test va être soit "1" ou indéfini. S'il y a quelque chose dans $model->test, ensemble $review à "1" sinon définissez-le égal à ''.

Parce que ce n'est pas Perl 5.10, je ne peux pas utiliser le nouvel opérateur défini ou or. Ma première réaction a été d'utiliser l'opérateur ternaire comme celui-ci ...

defined($model->test) ? $review = "1" : $review = '';

mais cela n'a pas fonctionné non plus.

Quelqu'un a-t-il une idée de comment attribuer cela plus efficacement? Janie

26
Jane WIlkie

J'écrirais habituellement ceci comme:

$review = ( defined($model->test) ? 1 : '' );

où les parenthèses sont pour plus de clarté pour les autres personnes lisant le code.

37
Greg D'Arcy

Vous avez un problème de priorité. Ce que vous avez est le même que

( defined($model->test) ? $review="1" : $review ) = '';

Vous pourriez le faire fonctionner avec des parens.

my $review; $model->test ? ( $review='1' ) : ( $review='' );

Mais il est beaucoup plus propre de déplacer l'affectation.

my $review = $model->test ? '1' : '';

Bien sûr, vous pouvez simplement utiliser

my $review = $model->test || '';

Mais pourquoi changer undef en une chaîne vide?

my $review = $model->test;
20
ikegami

$model->test va être soit "1" ou indéfini. S'il y a quelque chose dans $model->test, ensemble $review à "1" sinon définissez-le ''

Ensuite, utilisez simplement ceci:

$review = $model->test || "";
10
tchrist

Outre l'opérateur conditionnel, j'aime souvent utiliser do, qui renvoie la valeur de la dernière expression évaluée:

my $review = do {
     if( ... ) { 'foo' }
  elsif( ... ) { 'bar' }
  elsif( ... ) { 'baz' }
  else         { 'defaut' }
  };
7
brian d foy

Tout d'abord, "Cela n'a pas fonctionné non plus" n'est pas la chose la plus utile que vous puissiez nous dire. Il est important de savoir exactement comment cela n'a pas fonctionné: qu'est-ce que cela a fait, à quoi vous attendiez-vous et comment diffèrent-ils?

Mais le problème avec

defined($model->test) ? $review="1" : $review='';

est la priorité de l'opérateur. L'opérateur conditionnel ? : se lie plus étroitement que l'opérateur d'affectation =, donc ce qui précède équivaut à:

(defined($model->test) ? $review="1" : $review) = '';

Donc si $model->test est défini, il fait l'équivalent de

$review = "1" = '';

Vous pouvez résoudre ce problème avec des parenthèses:

defined($model->test) ? ($review="1") : ($review='');

Mais vraiment, pourquoi voudriez-vous? L'opérateur conditionnel (ternaire) est utile lorsque vous souhaitez utiliser le résultat. Si le résultat va être rejeté, comme c'est le cas ici, il est plus clair (et, comme vous l'avez vu, moins sujet aux erreurs) d'utiliser une instruction if/else:

if (defined($model->test) {
    $review = "1";
}
else {
    $review = "";
}

ou, si vous insistez pour l'écrire sur une seule ligne:

if (defined($model->test) { $review = "1"; } else { $review = ""; }

Si vous voulez vraiment utiliser une expression conditionnelle, vous pouvez le faire:

$review = defined($model->test) ? "1" : "";

ce qui est probablement une façon raisonnable de le faire.

MAIS:

L'opérateur defined lui-même donne soit "1" (vrai ou "" (faux). donc le tout peut être réduit à:

$review = defined($model->test);
2
Keith Thompson

Je suppose que $model->test est censé renvoyer une valeur vraie ou fausse.

Sauf si elle indique spécifiquement que la fausse valeur est undef, la méthode peut être réécrite pour commencer à renvoyer une autre fausse valeur à la place. Ce qui casserait tout ce qui ne vérifie que si la valeur est définie.
(Je pense que c'est un bogue que la méthode renvoie undef au lieu de la fausse valeur canonique.)

Donc, la meilleure façon de définir $review est de tester la véracité de la valeur retournée; pas sa définition.

my $review = $model->test ? 1 : '';

Je voudrais souligner que cela contient toujours un bug. Si vous voulez pouvoir utiliser la valeur comme un nombre, il émettra des avertissements si elle était fausse.

Pour résoudre ce problème, vous devez retourner !1 (fausse valeur canonique), qui renverra une valeur qui est la chaîne '', mais a également la valeur numérique de 0.

my $review = $model->test ? 1 : !1;

Notez qu'il pourrait être simplifié pour simplement:

my $review = !! $model->test; # invert it twice

Si vous ne souhaitez modifier la valeur que lorsqu'elle est fausse, vous pouvez utiliser l'opérateur or || .

my $review = $model->test || !1;

Si vous ne voulez vraiment savoir que si elle est définie, ou pourquoi ne pas simplement utiliser defined .

my $review = defined $model->test;

Si vous souhaitez modifier la valeur uniquement lorsqu'elle n'est pas définie et que vous avez Perl 5.10 ou une version plus récente, vous pouvez utiliser l'opérateur defined-or (//) .

my $review = $model->test // !1;

Sur un Perl plus ancien, cela nécessiterait plus d'un instruction .

my $review = $model->test;
$review = !1 unless defined $review;
2
Brad Gilbert
my $result = defined $model->test ? '1' : '';
1
zgpmax