Как я использую массив в качестве атрибута объекта в Perl?

Я нуждаюсь в некоторой помощи относительно массивов в 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 является массивом, я не мог заставить его работать, я подразумеваю, что относительные пути не печатаются.

7
задан Greg Bacon 2 April 2010 в 13:26
поделиться

3 ответа

Если вы включите директиву 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
9
ответ дан 6 December 2019 в 12:48
поделиться

Еще один способ сократить ввод текста - использовать 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.

4
ответ дан 6 December 2019 в 12:48
поделиться

Как только вы поймете ответ @ 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";
3
ответ дан 6 December 2019 в 12:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: