2012-03-20 11 views
17

Il perldocs dire quanto segue a proposito last:Perl: Perché "last" non può essere utilizzato per uscire da grep o map?

last non può essere utilizzato per uscire da un blocco che restituisce un valore come eval {}, sub {} o do {}, e non dovrebbe essere utilizzato per uscire da un grep() o una mappa() operazione.

Perché dovrebbe essere evitato in un grep() omappa()? Sono particolarmente curioso della mappa poiché è un'alternativa al costrutto foreach. I dottori sembrano insistere nel non fare qualcosa senza descrivere le conseguenze.

+3

mappa trasforma un elenco in un altro elenco, quindi ogni richiamo mappa dovrebbe restituire un elemento – perreal

+0

Ottengo l'errore 'Can not" last "al di fuori di un blocco di loop' cercando di uscire' map' con 'last' utilizzando perl v5. 14.1 in WinXP. – TLP

+0

@TLP: E questo è stato il caso almeno dal Perl v5.10.1. Sto indovinando che questo linguaggio "non dovrebbe" è un residuo di una versione precedente di Perl quando deve aver causato un comportamento strano. – ruakh

risposta

8

Innanzitutto, rendersi conto che grep e map sono trasparenti per next, last e redo, proprio come if è.

$ perl -e' 
    print "A"; 
    for (8,9) { 
     print "B"; 
     print map { print "C"; next; print "D"; $_ } 1,2,3; 
     print "E"; 
    } 
    print "F\n"; 
' 
ABCBCF 

Ma i documenti non dice lastnon può essere utilizzato per uscire map, si dice che non dovrebbe utilizzato. Non è chiaro cosa significhi.

  • Non li usano pensando che interesseranno map e grep?
  • Non li usi in questo modo perché il tuo lettore potrebbe pensare che influiscano su map e grep?
  • Non li usi in questo modo perché può lasciare Perl in uno stato traballante?
  • Non utilizzarli in questo modo perché il comportamento potrebbe cambiare in futuro?

Non so.

Io non credo che sia # 3 perché non so di eventuali cattivi effetti collaterali dell'utilizzo di next, last e redo lasciare un map o grep callback.

La cosa divertente, lasciando map e grep utilizzando un costrutto di loop non avvisa nemmeno se si lascia un sub nello stesso modo.

$ perl -wE'while (1) { map { last; } 1; }' 

$ perl -wE'while (1) { sub { last; }->(); }' 
Exiting subroutine via last at -e line 1. 
+2

Sono sicuro che l'intenzione è che 'last' (e' next') non devono essere utilizzati per uscire dal ciclo implicita in '' map' o grep' perché in realtà esce da un * blocco contenitore *. Si noti in particolare che mentre un 'ultimo' a livello di file è illegale, 'stampa" A "; stampare la mappa {stampare "B"; ultimo; stampare "C";} 1,2,3; stampa "Z"; 'stampa solo' AB' e quindi esce dall'intero programma. La linea di fondo è che 'map' fornisce una * mappatura * da una lista all'altra e ** non è **, come diceva l'OP, un'alternativa a' foreach'. – Borodin

+0

@Borodin, Re "perché in realtà esce da un blocco contenitore", è una delle possibili * interpretazioni * che ho menzionato. Non è ciò che i documenti doc in realtà * dicono *, e non offrite assolutamente alcuna prova a sostegno della vostra affermazione che deve essere sicuramente l'interpretazione corretta. Ri "Nota in particolare", allora perché la documentazione non dice di non usare 'last' per uscire da un blocco" se "e" allora "? Esce anche un "blocco contenitore". Stai respingendo la mia affermazione secondo cui l'intento non è ovvio semplicemente affermando che è ovvio. Non sono impressionato Qual è stato il punto del tuo commento? – ikegami

+4

devi lavorare sulla tua aggressività e ipersensibilità. Quello che ho detto è che sono sicuro dell'intenzione della documentazione. Sì, era una delle tue alternative. Non ho commentato se il significato della documentazione fosse ovvio. Non ero affatto in disaccordo con te. Per favore calmati. – Borodin

7

map è significato per mappatura una lista all'altra. È certamente non è un'alternativa a foreach. Ho visto troppo spesso le cose come

map { print "$_\n" } @data; 

che impegna il peccato di utilizzare map per i suoi effetti collaterali e gettando via la lista risultante. Non prenderebbe in considerazione l'utilizzo di

my $x = 99; 
sqrt(my $y = $x * $x); 
print $y; 

e si otterrebbe un avviso.Per lo stesso motivo non si usa map quando si intende for.

Per una ragione pratica, consideriamo

print "A"; 
print map { print "B"; last; print "C";} 1,2,3; 
print "Z"; 

OUTPUT

AB 

quindi in questo caso la last esce l'intero programma. In generale, utilizzando last o next all'interno di un blocco map o grep viene chiuso il blocco contenente, se presente, oppure l'intero programma. Questo è qualcosa da evitare, quindi "last ... non deve essere utilizzato per uscire da un'operazione grep() o map()".

+0

Ho significava un generatore elenco foreach alternativa, come come il * [documentazione] (http://perldoc.perl.org/functions/map.html) * dire '% hash = map {foo ($ _) => $ _ } @array; 'è un'alternativa per'% hash =(); foreach (@array) {$ hash {pippo ($ _)} = $ _; } ' – vol7ron

+0

Non c'è nessuna" stringa "risultante da eliminare quando si usa' map' nel contesto vuoto, quindi il primo argomento è fatalmente imperfetto. – ikegami

+2

Il tuo secondo argomento è ugualmente imperfetto. La gente fa 'func (my $ y = espressione)' per tutto il tempo: 'chomp (my $ x = <>);' 'utf8 :: decodificare (my $ decodificati = $ codificati);' Sia di coloro che ancora hanno valori di ritorno , che è più di uno che si può dire per 'map' in un contesto vuoto! – ikegami

2

In Perl esiste una discreta quantità di funzionalità che si sovrappongono tra for/foreach, grep e map. Tuttavia, solo perché è possibile utilizzare tutti per risolvere lo stesso problema, non significa che sono tutti lo strumento migliore per quel particolare lavoro (vedere: utilizzando un cacciavite per battere un chiodo).

  • grep: Il suo scopo è quello di filtrare un elenco e restituire il sottoinsieme risultante.
  • map: Lo scopo è modificare un elenco e restituire l'elenco modificato risultante.
  • for/foreach: Il suo scopo è quello di scorrere un elenco e fare qualcosa.

Ora, è possibile realizzare ogni uso di grep e map con for/foreach. grep e map sono essenzialmente zucchero sintattico per usi specifici dell'elaborazione dell'elenco (for/foreach) che sono particolarmente comuni e utili. Con la progettazione, per convenzione e con le migliori pratiche, scambiano alcune cose per maggiore praticità e chiarezza.

Uno di questi è che grep e map sono intesi per restituire un valore. Usarli in un contesto vuoto è scoraggiato e considerato come una violazione del Perl idiomatico. Se non si restituisce un valore, utilizzare for/foreach. Se si restituisce un valore, quindi last interrompe tale processo.

Se si seguono le best practice per Perl, l'utilizzo di grep e map restituirà sempre un valore, il che significa che è necessario evitare l'uso di last.

+0

+1. Non sono sicuro che Perl abbia delle migliori pratiche * ufficiali *, ma credo che Damian Conway lo faccia :) La maggior parte dei suoi punti sono generalmente accettati nella maggior parte dei linguaggi di programmazione. Comunque, stai attento. Ha inserito alcuni punti di preferenza personali senza comunicare che si tratta di preferenze personali. – vol7ron

+0

Perl potrebbe non avere un ** best practice ** ufficiale, ma questo non è solo un best practice del libro di Damian Conway. Vedrai la stessa raccomandazione nei perldoc (citata da Poster originale), nella 4 ° edizione di "[Programmazione Perl] (http://shop.oreilly.com/product/9780596004927.do)" e in "[ Efficace programmazione Perl] (http://www.effectiveperlprogramming.com/), 2a Edizione ". Tutto considerato, direi che lo rende così vicino come Perl arriva alle migliori pratiche ufficiali. ;-) –

+0

Non ho mai risposto, ma scoprirai che tutti quei ragazzi sono contributori di Perl CORE o lavorano insieme su progetti l'uno con l'altro. Sono tutti membri rispettati della comunità Perl e hanno avuto influenza sulla stessa lista non ufficiale di * Best * Practices. Basta rendersi conto che sono tutti pubblicati da O'Reilly e solo perché uno o due sono d'accordo, non li rende necessariamente * migliori *. Se guardi altrove, scoprirai che alcune delle loro cosiddette pratiche causano bug. Tuttavia, è meglio allontanarsi da TMTOWTDI e utilizzare uno stile e una convenzione popolari. --- Inoltre, volevo notare che ero l'OP. – vol7ron

Problemi correlati