простой Perl для перебора хэша, возвращенного из подпрограммы, в одной строке?

Допустим, у меня есть подпрограмма, которая возвращает результат хеширования. Я хочу перебрать пару ключ / значение из подпрограммы в моем родительском каталоге, и мне не хочется сначала сохранять результат в переменной.

Это кажется простым, но я вообще не знаю, как это сделать. Если метод возвращает хэш, я не знаю синтаксиса, необходимого для указания циклу ожидать, что хеш будет возвращен из метода. Если метод возвращает хэш-ссылку, я могу сделать

while( my($key,$value) = each ( %{ generate_hash() } )

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

Может ли кто-нибудь объяснить, какой абсурдно очевидный синтаксис мне здесь не хватает?


person dsollen    schedule 28.12.2015    source источник
comment
и не хочется сначала сохранять результат в переменной. Это действительно плохая причина для снижения читабельности вашего кода.   -  person ThisSuitIsBlackNot    schedule 29.12.2015
comment
Я не уверен, что вы сможете сделать это в рамках указанных ограничений. Для перебора хеша вам действительно нужен keys или each, и в обоих случаях вам нужно дважды «получить доступ» к хешу. (Я полагаю, вы могли бы в крайнем случае повторять один элемент за раз, но тогда вам все равно нужно будет использовать var, чтобы снова склеить их)   -  person Sobrique    schedule 29.12.2015


Ответы (2)


С оговоркой о том, что комментаторы правы и что это плохая идея, вы можете

  1. Поместите назначение в состав %{...}. По-прежнему не такой читабельный, не делает код более кратким, если вы не можете объединить объявление my с более ранним:

    my $foo;
    while (my ($k,$v) = each %{$foo //= generate_hash}) { ... }
    
  2. Убедитесь, что generate_hash возвращает ссылку на один и тот же хэш при каждом вызове. Таким образом, итератор, связанный с хешем, будет повторно использован и предоставит вам новый ключ. Конечно, проще всего добиться этого с помощью переменной:

    my $cached_generated_hash;
    sub generate_hash {
        return $cached_generated_hash //= do {
           ...
           { abc => 123, def => 456 }
        };
    }
    
person mob    schedule 28.12.2015

Согласитесь с @mob и комментаторами, нижеследующее представлено только для развлечения. Кажется непродуктивным, хотя мне будет интересно, сможет ли кто-нибудь вытащить что-нибудь хотя бы отдаленно вроде "абсурдно простого синтаксиса", чтобы сделать это :-)

Ах да, обратите внимание на однократный вызов genHash ().

$ ./foo.pl
Hello from genHash()
a=beta
a=2
a=alpha
a=1
a=gamma
a=3

$ cat ./foo.pl
#!/usr/bin/perl

use strict;

sub genHash() {
   print "Hello from genHash()\n";
   return { alpha => 1, beta => 2, gamma => 3 };
}

# There comes a point when you have to ask
# why you are even trying to swim upstream :-)
# ----- edit as per comments to remove unnecessary reference.
# original: foreach my $a ( %${ \( genHash() ) } ) {
# ------------------------------
foreach my $x ( %{ genHash() } ) {
   print "x=", $x, "\n";
}

$
person jgreve    schedule 28.12.2015
comment
Нет необходимости брать ссылку и сразу же разыменовывать ее, foreach my $foo (%{genHash()}){...} дает тот же результат. Обратите внимание, что вам никогда не следует лексизировать $a или $b, поскольку они зарезервированы для sort. - person ThisSuitIsBlackNot; 29.12.2015
comment
круто - спасибо, @ThisSuitIsBlackNot - отредактировал соответственно. Я регулярно использую% $ someref и не подумал попробовать его только с% {genHash ()} - person jgreve; 29.12.2015