使用内联哈希定义Perl while()=每个{}循环

时间:2018-06-16 00:52:24

标签: perl

我试图在每个循环中定义一个内联哈希,我的程序没有抛出任何错误但也没有执行print语句。是否可以定义如下的内联哈希:

while (my (key, value) = each %{ (apple  => "red", orange => "orange", grape  => "purple")}) { 
    print "something";
}

或者我可以在每个循环工作时如果我直接调用每个返回哈希的语句中的sub,如下所示:

sub returnsHash {
    my %fruits = (
        apple  => "red",
        orange => "orange",
        grape  => "purple",
    );
    return %fruits;
}

while (my (key, value) = each %{ returnsHash() }) { 
    print "something";
}

3 个答案:

答案 0 :(得分:11)

标量上下文中的列表/逗号运算符求值为标量上下文中计算的最后一项的结果。这意味着

each %{ apple => "red", orange => "orange", grape  => "purple" }

相当于

each %{ "purple" }

这是你的两个片段正在做的事情,但它是不受欢迎的,这是一个严格的违规行为。 (始终使用use strict; use warnings qw( all ); !!!)

您正在使用散列取消引用(%{ ... }),但您没有散列,更不用说您可以取消引用的散列的引用了。要构建哈希并返回对哈希的引用,请使用{ ... }

each %{ { apple  => "red", orange => "orange", grape  => "purple" } }

虽然这解决了问题,但只是揭示了另一个问题:你得到了无限循环。

eachkeysvalues使用的迭代器与哈希关联,而不是运算符。由于每次循环都在创建一个新的哈希,所以每次循环都会创建一个新的迭代器,所以你总是得到新创建的哈希的第一个元素,你的循环永远不会结束。

由于您无需按键查找项目,因此我不明白您为什么要使用哈希。您可以使用以下代码:

for (
   [ apple  => "red"    ],
   [ orange => "orange" ],
   [ grape  => "purple" ],
) {
   my ($key, $val) = @$_;
   ...
}

如果您从子目录中获得列表,以下是您如何编写上述内容。

use List::Util qw( pairs );

for (pairs(f())) {
   my ($key, $val) = @$_;
   ...
}

但这两个都创建了许多数组。由于没有破坏性的问题,我会使用以下方法来避免这个问题:

{
   my @kvs = f();
   while ( my ($key, $val) = splice(@kvs, 0, 2) ) {
      ...
   }
}

您也可以使用以下内容,但我认为很多人会对此感到困惑:

for (
   my @kvs = f();
   my ($key, $val) = splice(@kvs, 0, 2);
) {
   ...
}

答案 1 :(得分:5)

由于each仅适用于实际的变量,哈希或数组,因此无法完成。请参阅文档中的概要。 keysvalues同样如此。

第二次尝试也是如此,其中函数在每次迭代中也被重新调用。

请注意,尝试一个明智的事情是%{ {...} }(而不是%{ (...) }),因为%{}中的内容必须是哈希引用。这适用于两个尝试,因为函数返回一个哈希值,从而返回一个标量列表。 (根据第一个陈述,这仍然无济于事。)

我不确定需要什么,因为哈希可以在循环之前定义。此外,我建议在使用之前仔细查看each,因为它带有复杂性。

我认为你想迭代动态创建的这类对的列表的键值对。这是使用自定义迭代器(包装each使用的哈希迭代器)的方法。

use warnings;
use strict;
use feature 'say';

my $hit = get_each_it(a => 1, b => 2, c => 3);

while (my ($k, $v) = $hit->()) {
    say "$k => $v";
}

my ($k, $v) = $hit->();  # restarts the iterator
say "$k --> $v";
($k, $v) = $hit->();     # next (keeps state)
say "$k --> $v";

sub get_each_it {
    my %h = @_;
    return sub { return each %h }
}

重复和继续迭代(在散列用尽或单个调用之后)是each使用的散列迭代器的基本属性,并且在执行此操作时

  

只要给定的哈希值未经修改,您就可以依靠keysvalueseach重复返回相同的顺序。

请仔细研究这是如何运作的。

有关迭代器的详细信息,请参阅this article on Perl.comIterator模块中给出了迭代器的详细讨论以及教程。我不太了解这个模块,但是文档值得一读;每一个警告和警告都适用于each

如果您在哈希耗尽后不需要(或想要)重置迭代器以继续迭代的功能,则可以使用{ikegami评论中的替代迭代器{ {3}}

sub get_each_it {
    my @kv = @_;
    return sub { return splice @kv, 0, 2 }
}

这不会与each纠缠在一起,它也会按照提交的列表的顺序进行迭代。

请注意,通过splice的属性,生成器返回的每个代码引用仍保留其自己的迭代器,该迭代器在从各种代码段调用时保持其状态。小心使用。

另见closure

的介绍性说明

答案 2 :(得分:1)

执行您显然想做的事情的可能性是使用for循环。 (不是这样的)匿名散列进入初始化表达式。测试表达式是each的赋值,迭代表达式保持为空。

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

for (my %h = (
              apple => 'red',
              orange => 'orange',
              grape => 'purple',
             );
     my ($key, $value) = each(%h);
    ) {
  print("$key: $value\n");
}

这实际上可以看作是一种while循环,其循环的局部初始化。 %h仅在循环范围内。因此,for循环不是匿名的,可以与each一起使用,但在循环完成后不再存在。