2012-11-20 10 views
8

Continuo a ricevere :: confuso con -> quando si chiamano le subroutine dai moduli. So che :: è più correlato ai percorsi e in cui il modulo/subroutine è e -> viene utilizzato per gli oggetti, ma non capisco perché io possa scambiare apparentemente entrambi e non generare errori immediati. Ho moduli perl che fanno parte di un pacchetto più grande, ad es. FullProgram::Part1Perché '::' e '->' funzionano (ordinariamente) in modo intercambiabile quando si chiamano i metodi dai moduli Perl?

Sono quasi sempre alle prese con i moduli, ma lo sono ancora per motivi traballanti quando si tratta di oggetti in Perl, ma ho accidentalmente facendo questo:

FullProgram::Part1::subroutine1(); 

invece di

FullProgram::Part1->subroutine1(); 

così quando ho passando un ref hash per subroutine1 e stati attenti sull'utilizzo $class/$self a che fare con il riferimento all'oggetto e utilizzare accidentalmente :: finisco per tirare fuori i miei capelli chiedendo perché il mio hash rif sembra scomparire. Ho imparato la lezione, ma mi piacerebbe davvero una spiegazione della differenza. Ho letto i perldocs e vari siti web su questi, ma non ho visto alcun confronto tra i due (piuttosto difficile per google ...) Tutti apprezzati - sempre bene a capire quello che sto facendo!

+0

alcune buone risposte, difficili da scegliere, ma grazie - sicuramente chiarito le cose! – dgBP

risposta

7
FullProgram::Part1::subroutine1(); 

chiama la subroutine subroutine1 del pacchetto FullProgram::Part1 con una lista di parametri vuoto mentre

FullProgram::Part1->subroutine1(); 

chiama la stessa subroutine con il nome del pacchetto come primo argomento (si noti che diventa un po 'più complesso quando stai sottoclassi). Questa sintassi viene utilizzata con metodi costruttori che devono il nome della classe per la costruzione di oggetti di sottoclassi come

sub new { 
    my ($class, @args) = @_; 
    ... 
    return bless $thing, $class; 
} 

FYI: in Perl OO vedete $object->method(@args) che chiama Class::method con l'oggetto (un riferimento benedetto) come primo argomento, invece di il nome del pacchetto/classe. In un metodo come questo, la subroutine potrebbe funzionare in questo modo:

sub method { 
    my ($self, $foo, $bar) = @_; 
    $self->do_something_with($bar); 
    # ... 
} 

che chiamerà la subroutine do_something_with con l'oggetto come primo argomento ancora una volta seguito dal valore di $bar che era il secondo elemento della lista originariamente passato a method in @args. In questo modo l'oggetto stesso non si perde.

Per ulteriori informazioni su come l'albero di ereditarietà diventa importante quando si chiamano i metodi, vedere ikegami's answer!

+2

'$ object-> method (@args)' does not "chiama solo Class :: method". Chiama il primo metodo chiamato 'method' trovato nell'albero di ereditarietà. – ikegami

+0

Ho provato a menzionare quell'argomento senza rendere la mia risposta troppo complessa e rimosso il "giusto". Grazie, @ikegami! – memowe

9

Non c'è alcuna differenza intrinseca tra un sub di vaniglia e uno che è un metodo. È tutto nel modo in cui lo chiami.


Class::foo('a'); 

Questo chiamerà Class::foo. Se Class::foo non esiste, l'albero di ereditarietà non verrà controllato. Class::foo verranno passati solo gli argomenti forniti ('a').

È approssimativamente lo stesso: my $sub = \&Class::foo; $sub->('a');


Class->foo('a'); 

Ciò richiederà Class::foo, o foo in una delle sue classi base se Class::foo non esiste. L'invocante (ciò che si trova a sinistra dello ->) verrà passato come argomento.

E 'più o meno la stessa: my $sub = Class->can('foo'); $sub->('Class', 'a');

0

Storicamente, Perl Non aveva alcun OO. E funziona da pacchetti chiamati con sytax FullProgram::Part1::subroutine1();. O anche prima con la sintassi FullProgram'Part1'subroutine1(); (deprecata).

Successivamente, hanno implementato OOP con il segno ->, ma in realtà non è cambiato troppo. FullProgram::Part1->subroutine1(); chiamate subroutine1 e FullProgram::Part1 come 1 ° parametro. puoi vedere l'utilizzo di questo quando crei un oggetto: my $cgi = CGI->new(). Ora, quando chiami un metodo da questo oggetto, parte sinistra funge anche da primo parametro per funzionare: $cgi->param(''). Ecco come param riceve l'oggetto da cui ha chiamato (di solito denominato $self). Questo è tutto. -> è un hack per OOP. Di conseguenza, Perl non ha classi (i pacchetti funzionano come loro) ma ha oggetti (anche gli "oggetti" hack - sono benedetti scalari).

Offtop: anche è possibile chiamare con la sintassi my $cgi = new CGI;. Questo è uguale a CGI->new. Lo stesso quando dici print STDOUT "text\n";. Sì, sto solo chiamando lo IOHandle::print().

+1

Vale anche la pena ricordare che '->' fa in modo che perl cerchi l'albero di ereditarietà (ancora un altro hack tramite '@ ISA'). – friedo

5

Utilizzare entrambi!

use Module::Two; 

Module::Two::->class_method(); 

Nota che questo funziona ma ti protegge anche da un'ambiguità; il semplice

Module::Two->class_method(); 

viene interpretato come:

Module::Two()->class_method(); 

(chiamando la subroutine Due nel Modulo e cercando di chiamare class_method sul suo valore di ritorno - probabilmente con un conseguente errore di runtime o chiamando una classe o un'istanza metodo in una classe completamente diversa) se si verifica che ci sia un sub Two in Module - qualcosa che non si dovrebbe dipendere da un modo o dall'altro, poiché non è uno qualsiasi dello business del codice del modulo.

+1

lol +1 per il fatto divertente – PSIAlt

+0

L'ambiguità del parsing espressa qui è una delle mie cose "preferite" su Perl. Il fatto che la soluzione sia così brutta mi rende triste. – darch

+0

@darch: Non penso che sia brutto. Cosa ne pensi di '" Module :: Two "-> class_method()'? – ysth

Problemi correlati