2009-11-10 6 views
3

Quelle est la bonne façon d'écrire quelque chose d'équivalent au suivi:Comment initialiser des variables lexicales dans une condition Perl while?

while (my $first = $iterator->next && my $second = $iterator->next) { 
    # do work 
} 

Cela ne fonctionne pas - je voulais $first et $second une portée appropriée à l'intérieur de la boucle while.

+5

Vous n'avez pas dit ce que vous essayez de faire. Si votre objectif est de tirer deux éléments d'un itérateur à la fois, la sortie de la boucle s'il n'y a pas au moins deux éléments restant ou si l'un des éléments a une fausse valeur, cela fonctionne très bien et vos variables 'first' $ et '$ second' aura la portée appropriée. – Dan

+0

ce que tu fais avec && pour attraper la fin de la iterator? –

Répondre

17

Vous voulez des parenthèses autour des expressions d'affectation.

while ((my $first = $iterator->next) && (my $second = $iterator->next)) { 
    # ... 
} 

&& a une priorité supérieure =, de sorte que votre code original semblait qu'il essayait de faire une mission comme x && y = z.

+0

+1 encore plus court :) Ah – Andomar

+0

, Je pensais que je le faisais tout à fait faux, mais juste une erreur idiote. Merci! – Timmy

1

Essayez:

my $first; 
my $second; 
while (($first = $iterator->next) && ($second = $iterator->next)) { 
    # do work 
} 
+2

Pourquoi? Autrement dit, si '$ first' et' $ second' ne sont que des variables de boucle, pourquoi leur donner une portée plus large? – Telemachus

+0

@Telemachus: Essayé 'while (mon ($ a, $ b) = (1,1))' puis, mais oui la réponse de mobrule est meilleur (j'ai voté pour) :) – Andomar

8

J'ai tendance à écrire quelque chose comme ça comme:

while(my($first, $second) = map { ... } 1..2) { 
     ... 
     } 

Vous ne pouvez pas aimer cette syntaxe parce que vous n'êtes pas habitué à faire les choses de cette façon, mais il fait suite à une des règles de couple que je pense rendre le code plus facile :

  • Je ne tape pas la même chose deux fois
  • -je céder à toutes les variables à la fois
  • J'utilise la carte pour générer la liste quand je dois courir somethin g plus d'une fois.
  • Je n'utilise pas les opérateurs logiques gratuitement.

Cependant, il y a un autre problème. Vous devez déterminer ce que vous testez réellement dans la condition while, et le rendre apparent au programmeur suivant. Je ne sais pas pourquoi vous avez deux choses dans cette condition. Est-ce correct de lire l'itérateur s'il n'y a qu'une seule chose (c'est-à-dire ce qui arrive à l'homme étrange non traité)?

Une meilleure solution serait de montrer ce que vous essayez de faire sans montrer la mécanique.Ne sachant pas quoi que ce soit au sujet de votre iterator, je pourrais suggérer que vous décorez avec une autre méthode qui retourne deux éléments (ou peut-être la liste vide si elle est à la fin):

while(my($first, $second) = $iterator->read_two) { 
     ...; 
     } 

Si cela ne rend pas la situation clair, décorer avec une méthode pour poser une question particulière:

while($iterator->two_things_left) { 
     my($first, $second) = $iterator->read_two; 
     ...; 
     } 
11

C'est là and serait plus approprié que &&:

#!/usr/bin/perl 
use strict; use warnings; 

my $it = make_iterator(); 

while (my $first = $it->() and my $second = $it->()) { 
    print "$first\t$second\n"; 
} 

sub make_iterator { 
    my @x = qw(a b c); 
    return sub { 
     return shift(@x) if @x; 
     return; 
    }; 
} 

Sortie:

 
C:\Temp> it 
a  b 

Je serais tenté de prendre la cession à $second de la while (selon le sens de l'itérateur ne retourne pas un nombre pair d'éléments):

while (my $first = $it->()) { 
    defined(my $second = $it->()) 
     or warn "Iterator returned odd number of elements\n" 
     and last; 
    print "$first\t$second\n"; 
} 

sortie:

 
C:\Temp> it 
a  b 
Iterator returned odd number of elements 
Questions connexes