背景:我是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)安装软件的应用程序。该脚本需要用户通过命令行进行交互。
答案 0 :(得分:8)
一些小的Perl线索:
Data::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}}) {
^^ ^
options
是arrayref
的关键,您需要取消引用才能使用它。
至于你的另一个问题,建议使用更一般的pragma,特别是初学者
use strict;
use warnings;