循环遍历perl哈希中的匿名数组

时间:2013-06-24 03:00:43

标签: perl loops hashmap

背景:我是Perl的新手,我正在修补一个简单的脚本,该脚本循环遍历一个匿名数组的哈希值。

问题我似乎无法遍历数组。我得到的只是ARRAY(0x1663b78)

守则

#!/usr/bin/perl
package Foo;
use strict "vars";

sub new {
    my $class = shift;
    my $self = {
        distro  => "",
        pkg_mgr => "",
        options => ["PHP + Apache", "PHP + Lighthttpd", "PHP + Nginx", "RubyGems + Rails", "Node JS + NPM"]
    };

    bless $self, $class;

    return $self;
}

sub print_options {
    my($self) = @_;
    foreach($self->{options}) {
        print $_ . "\n";
    }
}

my $setup = new Foo();
$setup->print_options();

此外,如果我真的不需要私人或公共变量,有人可以告诉我使用use strict "vars";是否有用。我知道如何在PHP中执行此操作,但我不能在Perl中解决这个问题。

最后,我使用Perl的原因是因为最终我要创建一个为服务器(包括PHP)安装软件的应用程序。该脚本需要用户通过命令行进行交互。

3 个答案:

答案 0 :(得分:8)

一些小的Perl线索:

  • 每当遇到此类问题时,请使用Data::DumperData::Dumper将帮助您了解结构。
  • 如果你要去面向所有物体,那就去全力以赴吧。你有构造函数和方法。方法应返回值,并对这些值进行操作。每个方法和构造函数应尽可能独立,并且对整体对象结构知之甚少。
  • main包中操作。你应该翻转你的程序。最后两个语句应位于顶部,并在下面定义您的包。

如果您在调用时使用了Data::Dumper并转储了$self的数据,您会发现$self是一个包含三个密钥的哈希,options key指向匿名数组。

为了做你想做的事,你必须解除引用那个匿名数组:

sub print_options {
    my($self) = @_;
    for ( @{$self->{options} } ) {
        print $_ . "\n";
    }
}

但是,让我们清理您的程序,使其成为一个完整的课程。首先,方法永远不会打印 - 它们返回值。因此,您不应该使用print_options方法。相反,它应该返回数组(或对数组的引用)。

此外,您的构造函数不必知道Options的结构。怎么改变它怎么办?让我们来看一个改变的程序:

#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);

my $setup = Foo->new;
for my $option ( $setup->Option ) {
    say $option;
}

package Foo;

sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
    $self->Option("PHP + Apache");
    $self->Option("PHP + Lighthttpd");
    $self->Option("PHP + Nginx");
    $self->Option("RubyGems + Rails");
    $self->Option("Node JS + NPM");
    return $self;
}

sub Distro {
    my $self   = shift;
    my $distro = shift;
    if ( defined $distro ) {
        $self->{DISTRO} = $distro;
    }
    return $self->{DISTRO};
}

sub Package_Manager {
    my $self    = shift;
    my $package = shift;
    if ( defined $package ) {
        $self->{PACKAGE} = $package;
    }
    return $self->{PACKAGE};
}

sub Option {
    my $self = shift;
    my $option = shift;;

    if ( not exists $self->{OPTION} ) {
        $self->{OPTION} = [];
    }

    if ( defined $option ) {
        push @{ $self->{OPTION} }, $option;
    }
    my @array = @{ $self->{OPTION} };
    return wantarray ? @array : \@array;
}

首先,与PHP不同,Perl 在执行之前编译代码。因此,您可以在程序的底部定义包及其子例程。默认 main 包中的几行代码。如果我在Foo包中使用了包变量,我不会在程序中意外使用它。

请注意,我的方法或构造函数都不知道Foo对象的结构。当我在new构造函数中设置选项时,我调用Option方法进行设置。这样,如果我改变了存储选项的方式,我只需要更改我的Option方法,而不必担心我的包中的其他位置必须更改。它还简化了我的程序并使其更容易支持。

通过使我的Option方法设置或获取我的选项,我简化了代码。我可以看到我在匿名数组中存储选项,显然我在返回对象时需要取消引用它。我喜欢使用wantarray并为用户提供他们想要数组还是数组引用的选项。

请注意,我不会简单地返回$self->{OPTION}。它是对数组的引用,应该有效,但是如果我返回它,我将返回该对象的内存位置!因此,如果用户更改了该引用,则他们将更改我的对象 而不通过我的方法 。因此,我创建另一个数组,并返回对它的引用。使用所有你想要的数组引用,你不会改变我的对象。

此代码不完整。我可以设置选项,但不能设置选项。有一种方法可以推送 pop 选项。相反,此时您只能返回整个列表,而不是修改它。

答案 1 :(得分:3)

$self->{options}不是数组,而是数组的引用。您需要取消引用它才能迭代其值。

my @options = @{ $self=>{options} };

答案 2 :(得分:0)

您需要进行以下更改。

foreach(@{$self->{options}}) {
        ^^                ^

optionsarrayref的关键,您需要取消引用才能使用它。

至于你的另一个问题,建议使用更一般的pragma,特别是初学者

use strict;
use warnings;