2010-04-01 8 views
7

Necesito ayuda con respecto a las matrices en Perl¿Cómo uso una matriz como un atributo de objeto en Perl?

Este es el constructor que tengo.

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

(El código ha sido modificado de acuerdo con las sugerencias de los 'gbacon', gracias)

estoy empujando las rutas relativas en serie '' includeobjects en una dinámica camino. Los includepaths se leen desde un archivo xml y se insertan en este conjunto.

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

Así, el includeobject será así:

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

estoy usando esta línea de juego de incluir el trazado de

$newPacket->SetIncludePath(@includeobjects); 

También en PacketInput.pm, tengo

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

Tengo muchos pa ckets, así que estoy recorriendo cada paquete

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

Los métodos get y set funcionan bien para PacketName. Pero como IncludePath es una matriz, no pude hacer que funcione, es decir, las rutas relativas no se están imprimiendo.

+2

Ow my eyes. ¿Por qué no estás usando 'use strict; usa advertencias; '? – Ether

+0

gracias por señalarlo !! Ahora los estoy usando. :) – superstar

+1

La asignación a '@ includeobjects' tiene un error de sintaxis que no permitirá que su programa se ejecute en absoluto (que puede corregir cambiándolo a' @includeobjects = qw [./input/myMockPacketName ./input/myPacket /my3/*.txt ./input/myPacket/in.html]; '). Copie y pegue para que podamos ayudarlo a corregir el código en lugar de adivinar de qué se trata. –

Respuesta

9

Si habilita el pragma estricta, el código no incluso compilar:

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.

No utilice @ no indicada en las llaves porque va a confundir al analizador. Recomiendo eliminarlos por completo para evitar confundir a los lectores humanos con su código.

Se parecen querer tirar de todos los valores de atributo de los argumentos para el constructor, por lo que seguirá pelando los valores escalares con shift, y luego todo lo que dejó debe ser la ruta de inclusión.

Supongo que los componentes de la ruta include serán simples escalares y no referencias; si este es el caso, entonces querrá hacer copias profundas para mayor seguridad.

sub new { 
    my $class = shift; 

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

    bless $Packet, $class; 
} 

Tenga en cuenta que no hay necesidad de almacenar el objeto bendito en una variable temporal y luego volver inmediatamente a causa de la semantics of Perl subs:

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

Los métodos más adelante también harán uso de esta característica.

Dado el constructor anterior, se convierte en GetIncludePath

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

Hay un par de cosas que hacer aquí. En primer lugar, tenga en cuenta que tenemos cuidado de devolver una copia de la ruta de inclusión en lugar de una referencia directa a la matriz interna.De esta forma, el usuario puede modificar el valor devuelto desde GetIncludePath sin tener que preocuparse por desordenar el estado del paquete.

El wantarray operator permite a un submarino determinar el contexto de su llamada y responder en consecuencia. En contexto de lista, GetIncludePath devolverá la lista de valores en la matriz. De lo contrario, devuelve una referencia a una copia de la matriz. De esta manera, el código de cliente puede llamar ya sea como en

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

o

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

SetIncludePath es entonces

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

Tenga en cuenta que podría haber utilizado un código similar en el constructor en lugar de eliminar un parámetro a la vez con shift.

puede utilizar la clase definida anteriormente como en

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

Salida:

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

Intenté implementar los cambios y traté de imprimir la matriz @ {$ Packet -> {_ IncludePath}} de GetIncludePath, y no aparece nada – superstar

+1

@superstar La matriz estará vacía inicialmente porque 'my @includeobjects =() 'en el constructor crea una nueva matriz vacía. Código como' $ packet-> SetIncludePath (qw/foo bar baz /) 'le dará un valor interesante. ¿Hizo esto en su prueba? –

+0

No lo hice hasta ahora. ¡Trataré de implementarlo de inmediato! – superstar

3

Una vez que entienda @gbacon's answer, se puede ahorrar algo de mecanografía utilizando 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

Otra forma de reducir el tipeo es usar 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; 

Salida Moose::Manual::Unsweetened para otro ejemplo de cómo Moose ahorra tiempo.

Si se mantienen firmes en su deseo de aprender Perl clásica programación orientada a objetos, leer los siguientes artículos: perldocperlboot, perltoot, perlfreftut y perldsc.

Un gran libro sobre Perl OO clásico es Damian Conway's Object Oriented Perl. Le dará una idea de las posibilidades en el objeto de Perl.

+1

Clase :: El accesorio es una alternativa razonable si Moos está completamente fuera de cuestión. Pero Moose rocas. – Ether

+0

Gracias por la documentación y por el libro sugerido – superstar

+2

Nada en contra de Moose, pero no diría que uno de sus beneficios es la reducción de tipeo. Creo que es demasiado detallado y esperamos el día en que pueda generar el código de Moose a partir de una descripción de texto de la clase. –

Cuestiones relacionadas