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

Gor*_*ven 2 perl

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

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

或者我不能在每个循环工作时,如果我直接调用每个返回如下所示的散列的语句中的sub:

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

while (my (key, value) = each %{ returnsHash() }) { 
    print "something";
}
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 11

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

each %{ apple => "red", orange => "orange", grape  => "purple" }
Run Code Online (Sandbox Code Playgroud)

相当于

each %{ "purple" }
Run Code Online (Sandbox Code Playgroud)

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

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

each %{ { apple  => "red", orange => "orange", grape  => "purple" } }
Run Code Online (Sandbox Code Playgroud)

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

迭代器由哈希使用each,keysvalues与哈希关联,而不是运算符.由于每次循环都在创建一个新的哈希,因此每次循环都会创建一个新的迭代器,因此您将始终获得新创建的哈希的第一个元素,并且您的循环将永远不会结束.

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

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

如果你从sub获得列表,以下是你如何编写上面的内容.

use List::Util qw( pairs );

for (pairs(f())) {
   my ($key, $val) = @$_;
   ...
}
Run Code Online (Sandbox Code Playgroud)

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

{
   my @kvs = f();
   while ( my ($key, $val) = splice(@kvs, 0, 2) ) {
      ...
   }
}
Run Code Online (Sandbox Code Playgroud)

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

for (
   my @kvs = f();
   my ($key, $val) = splice(@kvs, 0, 2);
) {
   ...
}
Run Code Online (Sandbox Code Playgroud)


zdi*_*dim 5

这是不可能的,因为每个只能按预期使用实际变量,散列或数组.请参阅文档中的概要.这同样适用于.

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

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


我不确定需要什么,因为哈希可以在循环之前定义.此外,我建议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 }
}
Run Code Online (Sandbox Code Playgroud)

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

只要给定的散列未经修改,您就可以依赖keys,valueseach重复返回相同的顺序.

请仔细研究这是如何工作的.

有关迭代器的详细信息,请参阅Perl.com上的这篇文章.迭代器的详细讨论在Iterator模块中给出,并附有教程.我不太清楚这个模块,但是文档值得一读; 每一个警告和警告都适用each.


如果在哈希耗尽后你不需要(或想要)重置迭代器以继续迭代的能力,这里是使用splice的ikegami注释的替代迭代器

sub get_each_it {
    my @kv = @_;
    return sub { return splice @kv, 0, 2 }
}
Run Code Online (Sandbox Code Playgroud)

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

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

另请参阅perlfaq7中有关闭合的介绍性说明