在Perl中如何使用数组作为对象属性?

在Perl中如何使用数组作为对象属性?,perl,arrays,constructor,Perl,Arrays,Constructor,我需要一些关于Perl中数组的帮助 这是我的构造函数 下午六时 sub new { my $class = shift; my $Packet = { _PacketName => shift, _Platform => shift, _Version => shift, _Inclu

我需要一些关于Perl中数组的帮助

这是我的构造函数

下午六时

     sub new {
            my $class = shift;    
            my $Packet = {
                _PacketName => shift,
                _Platform  => shift,
                _Version => shift,
                _IncludePath => [@_],
            };

            bless $Packet, $class;
            return $Packet;
        }

        sub SetPacketName {
            my ( $Packet, $PacketName ) = @_;
            $Packet->{_PacketName} = $PacketName if defined($PacketName);
            return $Packet->{_PacketName};
        }

       sub SetIncludePath {
            my ( $Packet, @IncludePath ) = @_;
            $Packet->{_IncludePath} = \@IncludePath;
        }

         sub GetPacketName {
            my( $Packet ) = @_;
            return $Packet->{_PacketName};
        }

        sub GetIncludePath {
           my( $Packet ) = @_;
           @{ $Packet->{_IncludePath} };
        }
(代码已根据“gbacon”的建议进行了修改,谢谢)

我正在以动态方式将相对路径推送到“includeobjects”数组中。正在从xml文件读取IncludePath并将其推送到该数组中

# PacketInput.pm
if($element eq 'Include')
            {
             while( my( $key, $value ) = each( %attrs ))
                {
                if($key eq 'Path')
                    push(@includeobjects, $value);
                        }
                }
因此,includeobject将是这样的:

@includeobjects = (
    "./input/myMockPacketName",
    "./input/myPacket/my3/*.txt",
    "./input/myPacket/in.html",
);
我正在使用此行来设置包含路径

 $newPacket->SetIncludePath(@includeobjects);
同样在
PacketInput.pm
中,我有

sub CreateStringPath
{
    my $packet = shift;
    print "printing packet in CreateStringPath".$packet."\n";
    my $append = "";
    my @arr = @{$packet->GetIncludePath()};
    foreach my $inc (@arr)
    {
        $append = $append + $inc;
        print "print append :".$append."\n";
    }
}
我有很多数据包,所以我在每个数据包中循环

# PacketCreation.pl
my @packets = PacketInput::GetPackets();
foreach my $packet (PacketInput::GetPackets())
{
    print "printing packet in loop packet".$packet."\n";
    PacketInput::CreateStringPath($packet);
    $packet->CreateTar($platform, $input);
    $packet->GetValidateOutputFile($platform);
}

get和set方法对于PacketName很有效。但是由于IncludePath是一个数组,我无法使它工作,我的意思是没有打印相对路径。

如果启用严格的pragma,代码甚至无法编译:

Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 15. Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 29. Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 30. Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 40. 请注意,无需将祝福对象存储在临时变量中,然后立即返回它,因为:

如果未找到
return
,并且如果最后一条语句是表达式,则返回其值

下面的方法也将利用此功能

给定上面的构造函数,
GetIncludePath
变为

sub GetIncludePath {
  my( $Packet ) = @_;
  my @path = @{ $Packet->{_IncludePath} };
  wantarray ? @path : \@path;
}
这里发生了几件事。首先,请注意,我们小心地返回include路径的副本,而不是直接引用内部数组。这样,用户就可以修改从
GetIncludePath
返回的值,而不必担心数据包的状态会变糟

允许sub确定其调用的上下文并相应地响应。在列表上下文中,
GetIncludePath
将返回数组中的值列表。否则,它将返回对数组副本的引用。这样,客户机代码可以像中一样调用它

foreach my $path (@{ $packet->GetIncludePath }) { ... }

SetIncludePath
则为

sub SetIncludePath {
  my ( $Packet, @IncludePath ) = @_;
  $Packet->{_IncludePath} = \@IncludePath;
}
请注意,您可以在构造函数中使用类似的代码,而不是使用
shift
一次删除一个参数

您可以使用上面定义的类,如中所示

#! /usr/bin/perl

use strict;
use warnings;

use Packet;

sub print_packet {
  my($p) = @_;
  print $p->GetPacketName, "\n",
        map("  - [$_]\n", $p->GetIncludePath),
        "\n";
}

my $p = Packet->new("MyName", "platform", "v1.0", qw/ foo bar baz /);
print_packet $p;

my @includeobjects = (
    "./input/myMockPacketName",
    "./input/myPacket/my3/*.txt",
    "./input/myPacket/in.html",
);
$p->SetIncludePath(@includeobjects);
print_packet $p;

print "In scalar context:\n";
foreach my $path (@{ $p->GetIncludePath }) {
  print $path, "\n";
}
输出:

MyName - [foo] - [bar] - [baz] MyName - [./input/myMockPacketName] - [./input/myPacket/my3/*.txt] - [./input/myPacket/in.html] In scalar context: ./input/myMockPacketName ./input/myPacket/my3/*.txt ./input/myPacket/in.html 我的名字 -[富] -[酒吧] -[baz] 我的名字 -[./input/myMockPacketName] -[./input/myPacket/my3/*.txt] -[./input/myPacket/in.html] 在标量上下文中: ./input/myMockPacketName ./input/myPacket/my3/*.txt ./input/myPacket/in.html一旦理解,您可以使用以下命令保存一些键入内容:


另一种减少打字的方法是使用Moose

package Packet;
use Moose::Policy 'Moose::Policy::JavaAccessors';
use Moose;

has 'PacketName' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'Platform' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'Version' => (
    is       => 'rw',
    isa      => 'Int',
    required => 1,
);

has 'IncludePath' => (
    is       => 'ro',
    isa      => 'ArrayRef[Str]',
    default  => sub {[]},
    traits => [ 'Array' ],
    handles => {
        getIncludePath       => 'elements',
        getIncludePathMember => 'get',
        setIncludePathMember => 'set',
    },
);

__PACKAGE__->meta->make_immutable;
no Moose;
1;
查看关于驼鹿如何节省时间的另一个例子

如果您对学习经典Perl OOP有着坚定的愿望,请阅读以下文章:、和


这是一本关于经典PerlOO的好书。它将让您了解Perl对象中的可能性。

我尝试实现这些更改,并尝试从GetIncludePath打印数组@{$Packet->{u IncludePath},结果显示出来nothing@superstar数组最初将为空,因为构造函数中的
my@includeobjects=()
创建了一个新的空数组。像$packet->SetIncludePath(qw/foo-bar-baz/)这样的代码会给它一个有趣的值。你在测试中做过吗?我实际上使用的是$newPacket->SetIncludePath(@includeobjects);在另一个传递IncludeObject数组的模块中,我应该在GetIncludePath中获取这些数组值,但这并没有发生。@brian d foy:当我调用$packet->GetIncludePath时,我应该能够获得从SetIncludePath设置的数组值…对吗?@superstar查看更新答案中存储和检索include路径的工作示例。你的代码有什么不同?我的眼睛。为什么不使用
use strict;使用警告?感谢您指出!!现在我正在使用它们。:)
@includeobjects
的赋值有一个语法错误,根本不允许您的程序运行(您可以将其更改为
@includeobjects=qw[./input/myMockPacketName./input/myPacket/my3/*.txt./input/myPacket/in.html];
)。请复制并粘贴,这样我们就可以帮助您修复代码,而不是猜测它可能是什么。您添加的代码还包含语法错误:
push(@includeobjects,$value)
周围缺少大括号。复制并粘贴代码,而不是重新键入代码,这一点很重要。我修改了我的答案,使用了与您相同的
@includeobjects
,输出看起来很好。你已经告诉我们你没有得到的输出,那么你得到了什么?这也是重要的信息!我想我看到了问题所在。
PacketInput.pm
是否启用了
strict
pragma
GetIncludePath
返回一个数组,但
CreateStringPath
具有
@{$packet->GetIncludePath()}
,它将其视为对数组的引用。我将修改我的答案,使
GetIncludePath
在使用
wantarray
返回值时更加智能。如果Moos-eis完全不可能的话,Class::Accessor是一个合理的选择。但是驼鹿很厉害。谢谢你的文档和这本书,没有任何关于驼鹿的建议,但我不会说它的好处之一是减少打字。我认为这太冗长了,希望有一天它能从类的文本描述中生成Moose代码。@brian,这是一个有趣的想法。IME、Moose可能很冗长,但它比编写经典的PerlOOP类要紧凑得多。类型、强制和方法生成带来了巨大的节约。但我希望对象声明使用不那么冗长的标点语法。 MyName - [foo] - [bar] - [baz] MyName - [./input/myMockPacketName] - [./input/myPacket/my3/*.txt] - [./input/myPacket/in.html] In scalar context: ./input/myMockPacketName ./input/myPacket/my3/*.txt ./input/myPacket/in.html
#!/usr/bin/perl

package My::Class;
use strict; use warnings;
use base 'Class::Accessor::Fast';

__PACKAGE__->follow_best_practice;
__PACKAGE__->mk_accessors( qw(
    IncludePath
    PacketName
    Platform
    Version
));

use overload '""' => 'to_string';

sub to_string {
    my $self = shift;
    sprintf(
        "%s [ %s:%s ]: %s",
        $self->get_PacketName,
        $self->get_Platform,
        $self->get_Version,
        join(':', @{ $self->get_IncludePath })
    );
}

my $obj = My::Class->new({
        PacketName => 'dummy', Platform => 'Linux'
});
$obj->set_IncludePath([ qw( /home/include /opt/include )]);
$obj->set_Version( '1.05b' );
print "$obj\n";
package Packet;
use Moose::Policy 'Moose::Policy::JavaAccessors';
use Moose;

has 'PacketName' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'Platform' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'Version' => (
    is       => 'rw',
    isa      => 'Int',
    required => 1,
);

has 'IncludePath' => (
    is       => 'ro',
    isa      => 'ArrayRef[Str]',
    default  => sub {[]},
    traits => [ 'Array' ],
    handles => {
        getIncludePath       => 'elements',
        getIncludePathMember => 'get',
        setIncludePathMember => 'set',
    },
);

__PACKAGE__->meta->make_immutable;
no Moose;
1;