2011-10-19 11 views
6

Así que estaba haciendo mi negocio de Moosey y pensé que sería bueno usar una constante en estos lugares donde estoy usando números para aclarar lo que significan estos números o en caso de que cambien más tarde¿Por qué una subclase no hereda las constantes de sus padres?

So en la clase padre añadí el estándar 'uso constante'

package Parent; 
    use constant { 
     NO_LEVEL => 0, 
     MY_LEVEL => 1, 
     YOUR_LEVEL => 2, 
    }; 

package Child; 
extends 'Parent'; 

#just to demonstrate that child can or cannot access the constant 
sub printMyLevel{ 
print MY_LEVEL; 
} 

pero la clase niño no es consciente de las constantes seleccionadas en la matriz! doh!

Supongo que tengo que hacer algo de magia de Moose para que esto funcione bien, o algo completamente distinto. Mi búsqueda en este tema no obtuvo ningún resultado =/

Respuesta

3

Dado que las constantes son subrutinas y puede obtener la herencia llamándolas como métodos, el bit ya se ha cubierto hasta la muerte, aquí hay un giro diferente en las cosas.

Si sabe que está trabajando solamente en un solo archivo, puede utilizar las constantes léxicas a los paquetes de puente:

package Parent; 
    our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL); 
    *NO_LEVEL = \0; # this split declaration installs aliases to numbers 
    *MY_LEVEL = \1; # into the lexicals. since numbers are constants 
    *YOUR_LEVEL = \2; # to perl, the aliased names are also constants 

package Child; 

# just to demonstrate that anything below can access the constants 
sub printAll { 
    print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n"; 
} 

Child->printAll; # 0 1 2 

eval {$NO_LEVEL = 3} or print "error: [email protected]\n"; 
# error: Modification of a read-only value attempted at ... 

Si usted no necesita Perl a morir cuando se asigna a la constante, la declaración our se hace un poco más simple (y podría ser una my):

our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2); 

puede traer de vuelta a la naturaleza constante sin dejar de utilizar la sintaxis concisa con un poco de magia:

my $constant = sub {Internals::SvREADONLY($_[$_], 1) for 0 .. $#_}; 

package Parent; 
    $constant->(our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2)); 

package Child; 

# just to demonstrate that anything below can access the constants 
sub printAll { 
    print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n"; # interpolates :) 
} 

Child->printAll; # 0 1 2 

eval {$NO_LEVEL = 3} or print "error: [email protected]\n"; 
# error: Modification of a read-only value attempted at ... 

Por supuesto, puede omitir el coderef $constant en línea y de la magia:

package Parent; 
    Internals::SvREADONLY($_, 1) 
     for our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2); 
+0

+1 por una respuesta completa. Esto realmente me ayudó a entender la situación aquí. ¡Gracias, Eric! – qodeninja

10

Las constantes son subrutinas.

{ 
    package Parent; 
    use Moose; 
    use namespace::autoclean; 

    use constant { 
     NO_LEVEL => 0, 
     MY_LEVEL => 1, 
     YOUR_LEVEL => 2, 
    }; 
    __PACKAGE__->meta->make_immutable; 
}; 

{ 
    package Child; 
    use Moose; 
    use namespace::autoclean; 

    extends 'Parent'; 

    sub printMyLevel { 
     my $self = shift; 
     my $class = ref $self; 

     print $class->MY_LEVEL; 
    } 
    __PACKAGE__->meta->make_immutable; 
} 

package main; 

my $child = Child->new; 
$child->printMyLevel; 

Tenga en cuenta que las constantes son subrutinas con un prototipo vacío. perl aprovecha esto para alinearlos durante la compilación. Sin embargo, el método llama a ignorar los prototipos y, por lo tanto, las constantes heredadas a las que se accede de esta forma no se incluirán en línea.

+0

¿Por qué se pone el exterior {} en su conjunto?Empecé a hacer esto y alguien me insistió en que no era necesario. PD. Me gustaría acceder a las constantes directamente en la clase secundaria, así que parece que tengo que usar $ self-> CONSTANT ¿verdad? – qodeninja

+1

@nodebunny Encerré los paquetes en un alcance porque todo esto está en un solo archivo. Como se trata de datos de clase, me gusta hacer eso explícito. '$ self-> CONSTANT' funcionará, obviamente. –

+0

interesante, esto parece un idioma perl. entonces otra vez realmente no he tenido la idea de bloques hacia abajo todavía. {} <== es un bloque, ¿sí? +1 para el ejemplo completo. – qodeninja

4

Llámalos como método.

sub printMyLevel{ 
    my ($self,) = $_; 
    print $self->MY_LEVEL; 
} 
+0

+1 para explicar primero el $ self-> constante – qodeninja

6

Esto es en realidad mencionado en el documentation, aunque sólo sea de pasada:

"Constantes pertenecen al paquete que se definen en hacer referencia a una constante definida en otro paquete, especifique el pleno. nombre del paquete, como en Some::Package::CONSTANT. Las constantes pueden exportarse por módulos y también pueden llamarse como métodos de clase o instancia, es decir, como Some::Package->CONSTANT o como $obj->CONSTANT donde $obj es una instancia de Some::Package. Las subclases pueden definir sus propias constantes para sobrescribir aquellos en su clase base ".

+0

para que yo pueda hacer Parent :: CONSTANT too eh? Creo que me gusta eso mejor. Estaba buscando en los documentos de CPAN/Moose pensando que había una forma de Moose para hacerlo, pero esto también funciona. +1 para el documento – qodeninja

+0

'Parent :: CONSTANT' no le permite sobrescribirlo en clases secundarias. Todo depende de lo que quieras. –

+1

@Sinan: Por otro lado, 'Parent :: CONSTANT' tiene la ventaja de que se puede resolver en tiempo de compilación. –

2

La herencia afecta a las llamadas a los métodos ($x->m), punto.

+0

+1 solo por ser el eterno ikegami – qodeninja

Cuestiones relacionadas