3

Background: I am new to Perl and I am tinkering with a simple script that loops through a hash value that is an anonymous array.

The Issue I cannot seem to loop through the array. All I get is ARRAY(0x1663b78)

The Code

#!/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();

Also, if someone could kindly inform me if it's remotely useful to use use strict "vars"; if I really have no need for private or public variables. I know how I would do this in PHP but I can't wrap my head around this in Perl.

Lastly, my reason for using Perl is because eventually I'm going to make an application that installs software for servers (including PHP). This script will require user interaction via command line.

4

3 回答 3

9

一些小的 Perl 线索:

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

如果你在调用它时使用Data::Dumper并转储了数据$self,你会发现这$self是一个具有三个键的散列,并且options键指向一个匿名数组。

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

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在执行之前编译代码。因此,您可以在程序底部定义包及其子例程。以上几行代码在默认包中运行。如果我确实在我的包中使用了包变量Foo,我不会不小心在我的程序中使用它。

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

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

请注意,我不只是简单地返回$self->{OPTION}。它是对数组的引用,应该可以工作,但是如果我返回它,我将返回该对象的内存位置!因此,如果用户更改了该引用,他们将更改我的对象而无需通过我的方法。因此,我创建了另一个数组,并返回对它的引用。随心所欲地使用该数组引用,您不会更改我的对象。

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

于 2013-06-24T03:14:49.153 回答
4

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

my @options = @{ $self=>{options} };
于 2013-06-24T03:13:18.897 回答
1

您需要进行以下更改。

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

options是 an 的关键arrayref,您需要取消引用它才能使用它。

至于您的其他问题,建议使用更通用的一对编译指示,尤其是对于初学者

use strict;
use warnings;
于 2013-06-24T03:13:06.757 回答