Как я могу инициализировать лексические переменные в условии Perl while? - PullRequest
3 голосов
/ 11 ноября 2009

Как правильно написать что-то эквивалентное следующему:

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

Это не работает - я хотел $first и $second в нужной области внутри цикла while.

Ответы [ 4 ]

17 голосов
/ 11 ноября 2009

Вам нужны скобки вокруг выражений присваивания.

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

&& имеет более высокий приоритет, чем =, поэтому ваш исходный код выглядел так, как будто он пытался выполнить назначение, например x && y = z.

11 голосов
/ 11 ноября 2009

Здесь and будет более подходящим, чем &&:

#!/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;
    };
}

Выход:

C:\Temp> it
a       b

Я хотел бы получить присвоение $second из while (зависит от значения итератора, не возвращающего четное число элементов):

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

Выход:

C:\Temp> it
a       b
Iterator returned odd number of elements
8 голосов
/ 11 ноября 2009

Я склонен писать что-то вроде этого:

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

Вам может не понравиться этот синтаксис, потому что вы не привыкли делать что-то подобное, но он следует парам правил, которые, я думаю, делают код проще:

  • Я не набираю одно и то же дважды
  • Я назначаю всем переменным одновременно
  • Я использую карту для генерации списка, когда мне нужно запустить что-то более одного раза.
  • Я не использую логические операторы безвозмездно.

Однако есть еще одна проблема. Вы должны выяснить, что вы действительно тестируете в условии while, и сделать это очевидным для следующего программиста. Я не уверен, почему у вас есть две вещи в таком состоянии. Можно ли читать итератор, если есть только одна вещь (то есть, что происходит с необработанным нечетным человеком)?

Гораздо лучшим решением было бы показать, что вы пытаетесь сделать, не показывая механики. Ничего не зная о вашем итераторе, я могу предложить вам украсить его другим методом, который возвращает два элемента (или, может быть, пустой список, если он в конце):

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

Если это не прояснит ситуацию, украсьте ее методом, чтобы задать конкретный вопрос:

 while( $iterator->two_things_left ) {
      my( $first, $second ) = $iterator->read_two;
      ...;
      }
1 голос
/ 11 ноября 2009

Попробуйте:

my $first;
my $second;
while (($first = $iterator->next) && ($second = $iterator->next)) {
  # do work
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...