2013-10-03 13 views
24

Sto attraversando un periodo difficile a capire l'intersezione di OO Perl e my $self = shift; La documentazione su questi singoli elementi è ottima, ma nessuno di loro ha trovato il modo di lavorare insieme.

Ho usato Moose per creare moduli con attributi e, naturalmente, è utile fare riferimento all'attributo di un modulo all'interno di detto modulo. Mi è stato detto più e più volte di utilizzare my $self = shift; all'interno di una subroutine per assegnare gli attributi del modulo a quella variabile. Questo ha senso e funziona, ma quando sto anche passando argomenti alla subroutine, questo processo prende chiaramente il primo elemento dell'array @ARGV e lo assegna anche a $self.

Qualcuno può offrire una spiegazione su come utilizzare shift per ottenere l'accesso interno agli attributi di un modulo, passando anche argomenti nell'array @ARGV?

risposta

52

Prima di tutto, una subroutine non viene passata all'array @ARGV. Piuttosto tutti i parametri passati a una subroutine vengono appiattiti in una singola lista rappresentata da @_ all'interno della subroutine. L'array @ARGV è disponibile al livello più alto del tuo script, contenente gli argomenti della riga di comando passati allo script.

Ora, in Perl, quando si chiama un metodo su un oggetto, l'oggetto viene implicitamente passato come parametro al metodo.

Se si ignora l'ereditarietà,

$obj->doCoolStuff($a, $b); 

è equivalente a

doCoolStuff($obj, $a, $b); 

Il che significa che il contenuto del @_ nel metodo doCoolStuff sarebbe: @_ = ($obj, $a, $b);

Ora, il shift incorporato funzione, senza alcun parametro, sposta un elemento fuori dal d variabile di array efault @_. In questo caso, sarebbe $obj.

Così quando si fa $self = shift, si sta effettivamente dicendo $self = $obj.

Spero anche che questo spieghi come passare altri parametri a un metodo tramite la notazione ->. Continuando l'esempio che ho detto sopra, questo sarebbe come:

sub doCoolStuff { 
    # Remember @_ = ($obj, $a, $b) 
    my $self = shift; 
    my ($a, $b) = @_; 

Inoltre, mentre Moose è un livello di oggetto grande per Perl, non toglie il requisito che è necessario inizializzare il $self da soli in ogni metodo Ricorda sempre questo. Mentre linguaggio come C++ e Java inizializzano implicitamente il riferimento all'oggetto this, in Perl è necessario farlo esplicitamente per ogni metodo che scrivi.

+2

'shift' è impostato su' @ _' se chiamato da una subroutine o '@ ARGV' se chiamato dal codice di livello superiore. – cjm

+0

@cjm Proprio come te. Ne parlerò nella risposta. – Nikhil

+0

Fantastico. È molto utile. Mi sono imbattuto in un problema in cui il mio $ self = shift sembrava essere impostato sul primo argomento che ho effettivamente passato alla subroutine. Vale a dire, il primo elemento in @_ non era l'oggetto, ma era infatti il ​​primo argomento che ho fornito. Qualche ragione di alto livello ciò potrebbe accadere? (Ho lavorato su questo problema e non ho più il codice attuale) –

8

Nel codice di livello superiore, shift() è l'abbreviazione di shift(@ARGV). @ARGV contiene gli argomenti della riga di comando.

In un sottotitolo, shift() è l'abbreviazione di shift(@_). @_ contiene gli argomenti del sottotitolo.

Quindi my $self = shift; sta acquisendo il primo argomento del sottotitolo.Quando si chiama un metodo, l'invocante (ciò che resta dello ->) viene passato come primo parametro. In altre parole,

$o->method(@a) 

è simile a

my $sub = $o->can('method'); 
$sub->($o, @a); 

In questo esempio, my $self = shift; assegnerà $o a $self.

2

Se si chiama:

$myinstance->myMethod("my_parameter"); 

è lo stesso che facendo:

myMethod($myinstance, "my_parameter"); 

ma se lo fai:

myMethod("my_parameter"); 

solo "my_parameter" wil essere passato.

se poi dentro myMethod sempre si fa:

$self = shift @_; 

$ self sarà il riferimento all'oggetto quando myMethod id chiamato da un contesto oggetto
ma sarà "my_parameter" quando viene chiamato da un altro metodo all'interno su una modo procedurale.
Essere consapevoli di questo;

Problemi correlati