Я нуждаюсь в некоторой помощи относительно массивов в Perl
Это - конструктор, которого я имею.
BuildPacket.pm
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' динамическим способом. includepaths читаются из XML-файла и продвинуты в этот массив.
# 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);
}
Получение и методы установки хорошо работают для PacketName. Но так как IncludePath является массивом, я не мог заставить его работать, я подразумеваю, что относительные пути не печатаются.
Если вы включите директиву strict, код даже не компилируется:
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.
Не используйте @
без кавычек в ваших ключах, потому что это запутает синтаксический анализатор. Я рекомендую полностью удалить их, чтобы не запутать людей, читающих ваш код.
Похоже, вы хотите вытащить все значения атрибутов из аргументов в конструктор, поэтому продолжайте снимать скалярные значения с помощью shift
, а затем все, что осталось, должно быть путем включения.
Я предполагаю, что компоненты пути включения будут простыми скалярами, а не ссылками; в последнем случае вы захотите сделать глубокие копии в целях безопасности.
sub new {
my $class = shift;
my $Packet = {
_PacketName => shift,
_Platform => shift,
_Version => shift,
_IncludePath => [ @_ ],
};
bless $Packet, $class;
}
Обратите внимание, что нет необходимости сохранять благословенный объект во временной переменной, а затем немедленно возвращать его из-за семантики подпрограмм Perl :
Если не найдено
return
и если последний оператор является выражением, возвращается его значение.
Приведенные ниже методы также будут использовать эту функцию.
Учитывая вышеупомянутый конструктор, GetIncludePath
становится
sub GetIncludePath {
my( $Packet ) = @_;
my @path = @{ $Packet->{_IncludePath} };
wantarray ? @path : \@path;
}
Здесь происходит несколько вещей. Во-первых, обратите внимание, что мы стараемся возвращать копию пути включения, а не прямую ссылку на внутренний массив. Таким образом, пользователь может изменить значение, возвращаемое из GetIncludePath
, не беспокоясь о том, чтобы испортить состояние пакета.
Оператор wantarray
позволяет подпрограмме определять контекст своего вызова и отвечать соответствующим образом. В контексте списка GetIncludePath
вернет список значений в массиве.В противном случае он возвращает ссылку на копию массива. Таким образом, клиентский код может вызывать его либо как в
foreach my $path (@{ $packet->GetIncludePath }) { ... }
, либо как
foreach my $path ($packet->GetIncludePath) { ... }
SetIncludePath
тогда
sub SetIncludePath {
my ( $Packet, @IncludePath ) = @_;
$Packet->{_IncludePath} = \@IncludePath;
}
Обратите внимание, что вы могли бы использовать аналогичный код в конструкторе вместо удаления одного параметра за раз с помощью сдвиг
.
Вы можете использовать класс, определенный выше, как в
#! /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
Еще один способ сократить ввод текста - использовать 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;
Посмотрите Moose::Manual::Unsweetened для другого примера того, как Moose экономит время.
Если вы непреклонны в своем желании изучить классическое ООП на Perl, прочитайте следующие статьи perldoc: perlboot, perltoot, perlfreftut и perldsc.
Отличной книгой о классическом Perl OO является Damian Conway's Object Oriented Perl. Она даст вам представление о возможностях объектного Perl.
Как только вы поймете ответ @ gbacon , вы можете сэкономить на вводе текста, используя Class :: Accessor :: Fast :
#!/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";