goto
è quasi universalmente scoraggiato. Vale mai la pena utilizzare questa dichiarazione?
Commenti
Risposta
Questo è stato discusso più volte in Stack Overflow e Chris Gillum ha riassunto i possibili usi di goto
:
Uscita pulita da una funzione
Spesso in una funzione è possibile allocare risorse e dover uscire in più posizioni. I programmatori possono semplificare il codice inserendo il codice di pulizia delle risorse alla fine della funzione tutti i ” punti di uscita ” della funzione andrebbero letichetta di pulizia. In questo modo, non è necessario scrivere codice di pulizia in ogni ” punto di uscita ” della funzione.
Uscita da cicli nidificati
Se ti trovi in un ciclo nidificato e devi uscire da tutti i cicli, un goto può renderlo molto più pulito e semplice delle istruzioni break e dei controlli if.
Miglioramenti delle prestazioni di basso livello
Questo è valido solo nel codice critico per le prestazioni, ma le istruzioni goto vengono eseguite molto rapidamente e possono darti una spinta quando ti muovi attraverso una funzione. Questa è unarma a doppio taglio, tuttavia, perché un compilatore in genere non può ottimizzare il codice che contiene gotos.
Direi, come molti altri sostengono , che in tutti questi casi, lutilizzo di goto
viene utilizzato come mezzo per uscire da un angolo in cui ci si è codificati ed è generalmente un sintomo di codice che potrebbe essere refactoring .
Commenti
- Il primo problema è risolto molto chiaramente dai blocchi
finally
nelle lingue moderne e il secondo viene risolto con letichettabreak
s. Se ‘ sei bloccato con C, tuttavia,goto
è praticamente lunico modo per risolvere questi problemi in modo elegante. - Ottimi punti. Mi piace il modo in cui Java consente di rompere più livelli di loop
- @Chinmay – finalmente blocca solo applicare a 1) linguaggi moderni che li hanno eb) è possibile tollerare loverhead (la gestione delle eccezioni ha un overhead. ) Cioè, lutilizzo di
finally
è valido solo in queste condizioni. Ci sono situazioni molto rare, ma valide, in cui un goto è la strada da percorrere. - Va bene gente … che diamine è la differenza tra
break 3
obreak myLabel
egoto myLabel
. Oh, ‘ è giusta solo la parola chiave. Se utilizzibreak
,continue
o una parola chiave simile, stai utilizzando unagoto
(Se stai utilizzandofor, while, foreach, do/loop
stai utilizzando un goto condizionale.) - Informazioni sulle prestazioni di basso livello: il comportamento del processore moderno potrebbe essere difficile da prevedere (pipeline, esecuzione fuori servizio) quindi probabilmente nel 99% dei casi non ne vale la pena o addirittura potrebbe essere più lenta. @ MatthewWhited: Scoping. Se si immette lambito in un punto arbitrario, non è chiaro (agli umani) quali costruttori dovrebbero essere chiamati (il problema esiste anche in C).
Risposta
I costrutti del flusso di controllo di livello superiore tendono a corrispondere ai concetti nel dominio del problema. Un if / else è una decisione basata su una condizione. Un ciclo dice di eseguire ripetutamente unazione. Anche unistruzione break dice “lo stavamo facendo ripetutamente, ma ora dobbiamo fermarci”.
Unistruzione goto, daltra parte, tende a corrispondere a un concetto nel programma in esecuzione, non nel dominio problematico. Dice di continuare lesecuzione in un punto specificato nel programma . Qualcuno che legge il codice deve inferire cosa significa rispetto al dominio del problema.
Ovviamente tutti i costrutti di livello superiore possono essere definiti in termini di gotos e semplici rami condizionali . Ciò non significa che siano semplicemente gotos travestiti. Pensa a loro come a gotos limitati e sono le restrizioni che li rendono utili. Unistruzione break è implementata come un salto alla fine del ciclo che lo racchiude, ma è meglio pensarla come operando sul ciclo nel suo insieme.
A parità di condizioni, il codice la cui struttura riflette quella del dominio problematico tende ad essere più facile da leggere e mantenere.
Non ci sono casi in cui unistruzione goto è assolutamente richiesta (cè “s un teorema in tal senso), ma ci sono casi in cui può essere la soluzione meno pessima. Quei casi variano da da lingua a lingua, a seconda dei costrutti di livello superiore che la lingua supporta.
In C, ad esempio, credo che ci siano tre scenari di base in cui un goto è appropriato.
- Interruzione di un ciclo annidato. Ciò non sarebbe necessario se la lingua avesse unistruzione break etichettata.
- Salvataggio di una porzione di codice (in genere un corpo di funzione) in caso di errore o altro evento imprevisto . Questo non sarebbe necessario se il linguaggio avesse delle eccezioni.
- Implementazione di una macchina a stati finiti esplicita. In questo caso (e, credo, solo in questo caso) un goto corrisponde direttamente a un concetto nel dominio del problema, passando da uno stato a un altro stato specificato, dove lo stato corrente è rappresentato da quale blocco di codice è attualmente in esecuzione .
Daltra parte, una macchina a stati finiti esplicita può anche essere implementata con unistruzione switch allinterno di un ciclo. Questo ha il vantaggio che ogni stato inizia nella stessa posizione nel codice, il che può essere utile per il debug, ad esempio.
Luso principale di un goto in un linguaggio ragionevolmente moderno (uno che supporta if / altro e loops) serve a simulare un costrutto di flusso di controllo che manca nella lingua.
Commenti
- Questa è effettivamente la migliore risposta finora – piuttosto sorprendente, per una domanda che ha un anno e mezzo. 🙂
- +1 alla ” migliore risposta finora “. — ” Luso principale di goto in un linguaggio ragionevolmente moderno (uno che supporta if / else e loop) è simulare un flusso di controllo costruire che ‘ manca dalla lingua. ”
- Nella macchina a stati dellistruzione switch, ogni scrittura nella valore di controllo è davvero un
goto
. Le SSSM ‘ sono spesso buone strutture da usare, poiché parate lo stato SM dal costrutto di esecuzione, ma non ‘ per eliminare veramente ” gotos “. - ” A parità di condizioni, il codice la cui struttura riflette quella del dominio problematico tende ad essere più facile da leggere e gestire. ” Lo ‘ lo sapevo completamente da molto tempo, ma non avevo le parole per comunicarlo in modo così preciso in un modo che gli altri i programmatori possono e capiranno effettivamente. Grazie per questo.
- Il ” teorema del programma strutturato ” mi diverte, poiché tende a dimostrare chiaramente il sottolineare che lutilizzo di istruzioni di programmazione strutturata per emulare un goto è molto meno leggibile rispetto al semplice utilizzo di un goto!
Answer
Sicuramente dipende dal linguaggio di programmazione. Il motivo principale per cui goto
è stato controverso è a causa dei suoi effetti negativi che si verificano quando il compilatore ti consente di usarlo troppo liberamente. Possono sorgere problemi, ad esempio, se ti consente di utilizzare goto
in modo tale da poter accedere a una variabile non inizializzata o, peggio, passare a un altro metodo e fare confusione con la chiamata pila. Dovrebbe essere responsabilità del compilatore non consentire un flusso di controllo senza senso.
Java ha tentato di “risolvere” questo problema disabilitando completamente goto
. Tuttavia, Java consente di utilizzare return
allinterno di un blocco finally
e quindi causare inavvertitamente lingestione di uneccezione.Lo stesso problema è ancora lì: il compilatore non sta facendo il suo lavoro. La rimozione di goto
dalla lingua non ha risolto il problema.
In C #, goto
è sicuro quanto break
, continue
, try/catch/finally
e return
. Non ti permette di usare variabili non inizializzate, non ti permette di saltare fuori da un blocco finalmente, ecc. Il compilatore si lamenterà. Questo perché risolve il problema reale , che è come ho detto flusso di controllo senza senso. goto
non annulla magicamente lanalisi dellassegnazione definita e altri controlli ragionevoli del compilatore.
Commenti
- Il tuo punto è che C # ‘ s
goto
non è malvagio? Se è così, questo è il caso di ogni linguaggio moderno usato di routine con un costruttogoto
, non solo C # …
Risposta
Sì. Quando i tuoi loop sono annidati a diversi livelli di profondità, goto
è lunico modo per uscire con eleganza da un loop interno. Laltra opzione è impostare un flag e interrompere ogni ciclo se tale flag soddisfa una condizione. Questo è davvero brutto e piuttosto soggetto a errori. In questi casi, goto
è semplicemente migliore.
Ovviamente, listruzione break
etichettata Java fa lo stesso cosa, ma senza consentirti di saltare a un punto arbitrario nel codice, che risolve il problema in modo ordinato senza consentire le cose che rendono goto
malvagio.
Commenti
- goto non è mai una risposta elegante. Quando i tuoi loop sono annidati a diversi livelli di profondità, il tuo problema è che non sei riuscito a progettare il tuo codice per evitare i loop multinestizzati. il nemico. (Leggi i documenti ” Lambda: The Ultimate … “.) Utilizzando un goto per rompere i loop annidati diversi livelli profondi sta mettendo un cerotto su una frattura multipla aperta: può essere semplice ma non è ‘ la risposta giusta.
- E, naturalmente, cè non è mai un caso strano quando sono richiesti loop profondamente annidati? Essere un buon programmatore non è t solo per seguire le regole, ma anche per sapere quando infrangerle.
- @ JohnR.Strohm Mai dire mai. Se utilizzi termini come ” mai ” nella programmazione, ‘ chiaramente non hai trattato con casi dangolo, ottimizzazione, vincoli di risorse, ecc. Nei cicli profondamente annidati, goto è davvero il modo più pulito ed elegante per uscire dai cicli. ‘ non importa quanto ‘ hai riformattato il codice.
- @ JohnR.Strohm: il secondo più mancato caratteristica nel passaggio da VB.NET a C #: il ciclo
Do
. Perché? Perché posso cambiare lunico loop che necessita di uninterruzione profonda in unDo
loop e digitareExit Do
e lì ‘ noGoTo
. I cicli annidati si verificano continuamente. Rompere gli stack accade una certa% delle volte. - @ JohnR.Strohm Lunico motivo per cui dici ” goto non è mai una risposta elegante ” è perché hai deciso che goto non è mai una risposta elegante, e quindi qualsiasi soluzione che utilizza goto non può essere una risposta elegante.
Risposta
La maggior parte dello scoraggiamento proviene da una sorta di “religione” che è stata creata intorno a Dio Djikstra, che nei primi anni 60 aveva il potere indiscriminato di :
- salta ovunque in qualsiasi blocco di codice
- funzione non eseguita dallinizio
- cicli non eseguiti dallinizio
- inizializzazione della variabile saltata
- salta via da qualsiasi blocco di codice senza alcuna possibile pulizia.
Questo non ha più niente a che fare con il goto
dichiarazione dei linguaggi moderni, la cui esistenza è semplicemente dovuta al supporto del cr la scelta di strutture di codice diverse da quelle fornite dal linguaggio.
In particolare il primo punto principale sopra è più consentito e il secondo è pulito (se goto
fuori un blocco lo stack viene svolto correttamente e tutti i distruttori appropriati vengono chiamati)
Puoi fare riferimento a questa risposta per avere unidea di come anche il codice non lutilizzo di goto può essere illeggibile. Il problema non è goto in sé, ma il cattivo uso di esso.
Posso scrivere un intero programma senza utilizzare if
, solo for
. Ovviamente non sarà ben leggibile, avrà un aspetto goffo e inutilmente complicato.
Ma il problema non è for
. Sono io.
Cose come break
, continue
, throw
, bool needed=true; while(needed) {...}
e così via stanno notando più di mascheramento goto
per sfuggire alle scimitarre dei fanatici di Djikstrarian, che – 50 anni dopo linvenzione dei laguages moderni, vogliono ancora i loro prigionieri. Si sono dimenticati di cosa parlava Djikstra, si ricordano solo il titolo della sua nota (GOTO considerato dannoso, e non era nemmeno il suo titolo: è stato cambiato dalleditore) e biasima e bash, bash e incolpa ogni contruct che ha quei 4 lettera in sequenza.
È il 2011: è ora di capire che goto
ha a che fare con GOTO
dichiarazione su cui Djikstra era convincente.
Commenti
- ” Cose come break, continue , lancia, bool necessario = true; mentre (necessario) {…}, ecc. stanno notando più di masquerade goto ” Non ‘ sono daccordo con questo. Preferirei che ” cose come break ecc. Fossero limitate goto ” o qualcosa del genere. Il problema principale con goto è che di solito è troppo potente. Nella misura in cui lattuale goto è meno potente di Dijkstra ‘ s, la tua risposta va bene per me.
- @MuhammadAlkarouri: Sono totalmente daccordo. Hai appena trovato una formulazione migliore per esprimere esattamente il mio concetto. Il punto è che tali restrizioni a volte possono non essere applicabili e il tipo di restrizione di cui hai bisogno non è nella lingua. Quindi una cosa più ” potente “, meno specializzata, è ciò che ti rende in grado di aggirare il problema. Ad esempio, Java
break n
non è disponibile in C ++, quindigoto escape
, anche seescape
non è necessario che sia appena uscito dal ciclo n-ple.
Risposta
Lo strano goto qui o lì, fintanto che è locale per una funzione, raramente danneggia in modo significativo la leggibilità. Spesso ne beneficia attirando lattenzione sul fatto che cè qualcosa di insolito in questo codice che richiede luso di una struttura di controllo piuttosto insolita .
Se goto (locali) danneggiano in modo significativo la leggibilità, di solito è un segno che la funzione contenente goto è diventata troppo complessa.
Lultimo goto che ho inserito in un Un pezzo di codice C era quello di costruire una coppia di circuiti ad incastro. Non rientra nella normale definizione di uso “accettabile” di goto, ma la funzione è risultata significativamente più piccola e più chiara. Per evitare il goto sarebbe stata necessaria una violazione particolarmente complicata di DRY.
Commenti
- La risposta a questa domanda è espressa in modo molto conciso nel vecchio ” Lay ‘ s Potato Chips ” slogan: ” Scommetto che puoi ‘ non mangiarne solo uno “. Nel tuo esempio, hai due ” interlocking ” (qualunque cosa significhi, e io ‘ Scommetto che non sono ‘ abbastanza) loop, e il goto ti ha dato un buon prezzo. E laddetto alla manutenzione, che deve modificare quel codice dopo che sei stato investito da un autobus? Il goto renderà la sua vita più facile o più difficile? Questi due cicli devono essere ripensati?
Risposta
Penso che lintero problema sia stato un caso di abbaiare lalbero sbagliato.
GOTO in quanto tale non mi sembra problematico, ma piuttosto spesso è un sintomo di un vero peccato: il codice degli spaghetti.
Se il GOTO causa un maggiore attraversamento delle linee di controllo del flusso non va bene, punto. Se non attraversa nessuna linea di controllo del flusso è innocuo. Nella zona grigia in mezzo abbiamo cose come i salvataggi di loop, ci sono ancora alcuni linguaggi che non hanno aggiunto costrutti che coprono tutti i casi grigi legittimi.
Lunico caso in cui mi sono ritrovato a usarlo effettivamente in molti anni è il caso del ciclo in cui il punto di decisione è nel mezzo del ciclo. Ti rimane un codice duplicato, un flag o un GOTO. Trovo la soluzione GOTO la migliore delle tre. Non ci sono incroci di linee di controllo del flusso qui, è innocuo.
Commenti
- Il caso a cui alludi è talvolta soprannominato “loop e mezzo” o “N più un mezzo loop” ed è un famoso caso duso per
goto
che saltano in un ciclo (se la lingua lo consente; poiché laltro caso, saltare fuori dal ciclo nel mezzo, di solito è banale senzagoto
). - (Purtroppo, la maggior parte delle lingue proibisce di saltare in un ciclo.)
- @KonradRudolph: se implementi il ” ciclo ” con GOTO non cè nessunaltra struttura di loop in cui saltare.
- Penso che
goto
urli IL FLUSSO DI CONTROLLO QUI NON ‘ T FIT NORMALE PROGRAMMAZIONE STRUTTURATA MODELLI . Poiché i flussi di controllo che si adattano a schemi di programmazione strutturati sono più facili da ragionare rispetto a quelli che non ‘ t, si dovrebbe tentare di utilizzare tali schemi quando possibile; se il codice si adatta a tali schemi, non si dovrebbe ‘ gridare che non ‘ t. Daltra parte, nei casi in cui il codice ‘ non si adatta a tali schemi, gridare a riguardo potrebbe essere meglio che fingere che il codice si adatti quando in realtà non ‘ t. - @supercat Bene, immagina di esserti scritto un programma, e poi il vento lo soffia via dalle tue mani. Secondo la tua logica, non dovresti ‘ recuperarlo, perché inseguire la tua pianificazione non era ‘ nei tuoi programmi.
Risposta
Sì, goto può essere utilizzato a vantaggio dellesperienza dello sviluppatore: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/
Tuttavia, proprio come con qualsiasi strumento potente (puntatori, ereditarietà multipla, ecc.), uno deve essere disciplinato usandolo. Lesempio fornito nel collegamento utilizza PHP, che limita lutilizzo del costrutto goto alla stessa funzione / metodo e disabilita la possibilità di passare a un nuovo blocco di controllo (ad es. Loop, istruzione switch, ecc.)
Risposta
Dipende dalla lingua. È ancora ampiamente utilizzato nella programmazione Cobol, ad esempio. Ho anche lavorato su un dispositivo Barionet 50, il cui linguaggio di programmazione del firmware è uno dei primi dialetti BASIC che ovviamente richiede luso di Goto.
Risposta
goto
può essere utile quando si esegue il porting del codice assembler legacy in C. In primo luogo, unistruzione- la conversione tramite istruzione in C, utilizzando goto
in sostituzione dellistruzione assembler “s branch
, può abilitare il porting molto rapido.
Commenti
- Esatto, ma uno degli argomenti contro i
goto
è che ostacolano le ottimizzazioni del compilatore. - @Sapphire_Brick: molte ottimizzazioni del compilatore sono progettate attorno a determinati schemi di esecuzione. Se lattività da eseguire non ‘ si adatta ai modelli di esecuzione supportati, ” ostacolare le ” ottimizzazioni potrebbe non essere una brutta cosa.
Risposta
Direi di no. Dovrebbero sempre essere sostituiti con uno strumento più specifico per il problema che goto viene utilizzato per risolvere (a meno che non sia disponibile nella tua lingua). Ad esempio, le istruzioni break e le eccezioni risolvono problemi di loop escaping e precedentemente risolti da goto gestione degli errori.
Commenti
- I ‘ d sostengo che quando le lingue hanno entrambe queste funzioni,
goto
è in genere assente da queste lingue. - Ma è perché non ‘ non ne hai bisogno o perché le persone pensano di non ‘ non ne hanno bisogno?
- Le tue opinioni sono bigotte. Ci sono molti casi in cui
goto
è la cosa più vicina alla semantica del dominio del problema, qualsiasi altra cosa sarebbe un trucco sporco. - @ SK-logic: I don ‘ Non pensare che la parola ” bigotto ” significhi ciò che pensi significhi.
- @ Keith,
devoto intollerantemente alle proprie opinioni e pregiudizi ” – questo ‘ è quello che io osserva costantemente qui, con questo lotto con gli occhi bendati. ” Dovrebbe sempre essere sostituito ” sono fanatici ‘ almeno le parole. Niente di simile a unopinione corretta e sana, ma solo un puro fanatismo. Questo ” sempre ” non lascia spazio ad alcuna opinione alternativa, vedi?
Risposta
Direi di no. Se trovi la necessità di utilizzare GOTO, scommetto che cè bisogno di riprogettare il codice.
Commenti
- Forse, ma tu haven ‘ t fornito alcun ragionamento
- Dijkstra ha fornito il ragionamento, in dettaglio, decenni fa.
- Just Dogma. Nessuna risonanza. Nota: Djikstra NON È PIÙ UNA RISONATA VALIDA: si riferiva allistruzione BASIC o FORTRAN GOTO dei primi ‘ anni 60. Non hanno nulla a che fare con le cose davvero anemiche (rispetto al potere di quelle) di oggi.
- @EmilioGaravaglia Bene, la parte del suo ragionamento che si applica ancora oggi è che ‘ è molto facile scrivere codice di spaghetti usando way to many gotos. Tuttavia, con questa logica, non dovremmo ‘ utilizzare puntatori perché lutilizzo di tanti puntatori quanti
number of gotos needed to create problems
creerebbe un caos simile.
goto
è ciò che alla fine fa la cpu, ma non funziona bene con ciò che gli esseri umani hanno bisogno di comprendere e astrarre perché non cè segno sul bersaglio fine. Confronta con IntercalCOMEFROM
.goto
non è richiesto. È solo il modo più razionale di implementarli nei linguaggi imperativi, poiché è la cosa più vicina alla semantica stessa della transizione di stato. E la sua destinazione può essere abbastanza lontana dalla fonte, non ‘ ne ostacola la leggibilità. Il mio esempio preferito di tale codice è D.E. Knuth ‘ s implementazione del gioco Avventura.