2010-04-01 8 views
7

Ho bisogno di aiuto per quanto riguarda gli array in PerlCome utilizzare un array come attributo oggetto in Perl?

Questo è il costruttore che ho.

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} }; 
     } 

(Il codice è stato modificato in base ai suggerimenti dei 'gbacon', grazie)

sto spingendo i percorsi relativi in ​​una matrice 'includeobjects' in una dinamica modo. I file includep vengono letti da un file xml e vengono inseriti in questo array.

# PacketInput.pm 
if($element eq 'Include') 
      { 
      while(my($key, $value) = each(%attrs)) 
       { 
       if($key eq 'Path') 
        push(@includeobjects, $value); 
         } 
       } 

Così, l'includeobject sarà in questo modo:

@includeobjects = (
    "./input/myMockPacketName", 
    "./input/myPacket/my3/*.txt", 
    "./input/myPacket/in.html", 
); 

Sto usando questa linea per insieme include percorso

$newPacket->SetIncludePath(@includeobjects); 

Anche in PacketInput.pm, ho

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"; 
    } 
} 

Ho molte pa ckets, quindi sono scorrendo ogni pacchetto

# 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); 
} 

I metodi get e set funzionano bene per PacketName. Ma dal momento che IncludePath è un array, non riesco a farlo funzionare, voglio dire che i percorsi relativi non vengono stampati.

+2

Ow my eyes. Perché non stai usando 'use strict; usa avvertimenti; '? – Ether

+0

grazie per avermelo fatto notare !! Ora li sto usando. :) – superstar

+1

L'assegnazione a '@ includeobjects' ha un errore di sintassi che non consente al programma di funzionare affatto (che è possibile correggere modificandolo in' @includeobjects = qw [./input/myMockPacketName ./input/myPacket /my3/*.txt ./input/myPacket/in.html]; '). Si prega di copiare e incollare in modo che possiamo aiutarti a correggere il tuo codice invece di indovinare cosa potrebbe essere. –

risposta

9

Se si abilita il pragma rigorosa, il codice non ha nemmeno compilare:

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.

Non utilizzare @ non quotati nelle vostre chiavi perché sarà confondere il parser. Consiglio di rimuoverli completamente per evitare di confondere i lettori umani del tuo codice.

Sembra che vogliate estrarre tutti i valori degli attributi dagli argomenti al costruttore, quindi continuare a rimuovere i valori scalari con shift e quindi tutto ciò che rimane deve essere il percorso di inclusione.

Suppongo che i componenti del percorso di inclusione siano semplici scalari e non riferimenti; se quest'ultimo è il caso, allora ti consigliamo di fare copie profonde per sicurezza.

sub new { 
    my $class = shift; 

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

    bless $Packet, $class; 
} 

Nota che non c'è alcuna necessità di memorizzare l'oggetto benedetto in una variabile temporanea e poi subito a restituirlo a causa del semantics of Perl subs:

If no return is found and if the last statement is an expression, its value is returned.

metodi indicati potranno anche fare uso di questa funzione.

Dato il costruttore sopra, GetIncludePath diventa

sub GetIncludePath { 
    my($Packet) = @_; 
    my @path = @{ $Packet->{_IncludePath} }; 
    wantarray ? @path : \@path; 
} 

Ci sono un paio di cose che sta succedendo qui. Innanzitutto, si noti che stiamo attenti a restituire una copia del percorso di inclusione piuttosto che un riferimento diretto all'array interno.In questo modo, l'utente può modificare il valore restituito da GetIncludePath senza doversi preoccupare di spostare lo stato del pacchetto.

Il wantarray operator consente a un sub di determinare il contesto della propria chiamata e di rispondere di conseguenza. Nel contesto dell'elenco, GetIncludePath restituirà l'elenco di valori nell'array. In caso contrario, restituisce un riferimento a una copia dell'array. In questo modo, il codice cliente può chiamare sia come in

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

o

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

SetIncludePath è poi

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

Nota che si potrebbe avere utilizzato codice simile nel costruttore piuttosto che rimuovere un parametro alla volta con shift.

È possibile utilizzare la classe definita sopra come in

#! /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"; 
} 

uscita:

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
+0

Ho provato a implementare le modifiche e ho provato a stampare l'array @ {$ Packet -> {_ IncludePath}} da GetIncludePath e non mostra nulla – superstar

+1

@superstar L'array sarà inizialmente vuoto perché 'my @includeobjects =() 'nel costruttore crea un nuovo array vuoto. Codice come' $ packet-> SetIncludePath (qw/foo bar baz /) 'darà un valore interessante. Lo hai fatto nel tuo test? –

+0

Non l'ho fatto finora. Proverò a implementare subito! – superstar

3

Una volta capito @gbacon's answer, è possibile risparmiare un po 'di digitazione utilizzando 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"; 
4

Un altro modo per ridurre la digitazione è usare 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; 

Partenza Moose::Manual::Unsweetened per un altro esempio di come Moose consente di risparmiare tempo.

Se sei irremovibile nel vostro desiderio di imparare il Perl classica OOP, leggere i seguenti articoli: perldocperlboot, perltoot, perlfreftut e perldsc.

Un ottimo libro sul Perl OO classico è Damian Conway's Object Oriented Perl. Ti darà un senso delle possibilità nell'oggetto di Perl.

+1

Class :: Accessor è un'alternativa ragionevole se Moos eis è assolutamente fuori questione. Ma le rocce delle alci. – Ether

+0

Grazie per la documentazione e per il libro suggerito – superstar

+2

Niente contro Moose, ma non direi che uno dei suoi benefici è la riduzione della digitazione. Penso che sia troppo prolisso e attendo con ansia il giorno in cui può generare il codice Moose da una descrizione testuale della classe. –

Problemi correlati