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

djt*_*oms 2 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();
Run Code Online (Sandbox Code Playgroud)

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

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

Dav*_* W. 8

一些小的Perl线索:

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

如果您使用Data::Dumper并转储了$self调用它时的数据,您将意识到这$self是一个包含三个键的哈希,并且该options键指向一个匿名数组.

为了做你想做的事,你必须取消引用匿名数组:

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

但是,让我们清理你的程序,使它成为一个完整的类.首先,方法永远不会打印 - 它们返回值.因此,你不应该有一个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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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