goto
frarådes næsten universelt. Bruger dette udsagn nogensinde det?
Kommentarer
Svar
Dette er blevet diskuteret flere gange på Stack Overflow, og Chris Gillum opsummerede de mulige anvendelser af goto
:
Afslutter en funktion
Ofte tildeler du muligvis ressourcer i en funktion og har brug for at afslutte flere steder. Programmører kan forenkle deres kode ved at placere ressourceoprydningskoden i slutningen af funktionen, alle ” udgangspunkter ” af funktionen ville gå oprydningsetiketten. På denne måde behøver du ikke skrive oprydningskode ved hvert ” udgangspunkt ” af funktionen.
Afslutter nestede sløjfer
Hvis du er i en indlejret løkke og har brug for at bryde ud af alle sløjfer, en goto kan gøre dette meget renere og enklere end break-udsagn og if-checks.
Ydeevneforbedringer på lavt niveau
Dette er kun gyldigt i perf-kritisk kode, men goto-sætninger udføres meget hurtigt og kan give dig et boost, når du bevæger dig gennem en funktion. Dette er et dobbeltkantet sværd, men fordi en kompilator typisk ikke kan optimere kode, der indeholder fotos.
Jeg ville argumentere, som mange andre ville argumentere for , at i alle disse tilfælde bruges brugen af goto
som et middel til at komme ud af et hjørne, man kodede sig ind i, og er generelt et symptom på kode, der kunne refactored .
Kommentarer
- Det første problem løses meget pænt ved
finally
blokke på moderne sprog, og det andet løses med mærketbreak
s. Hvis du ‘ sidder fast med C dog,goto
er stort set den eneste måde at løse disse problemer elegant på. - Meget gode punkter. Jeg kan godt lide, hvordan Java tillader at bryde ud af flere niveauer af sløjfer
- @Chinmay – endelig kun blokerer gælder for 1) moderne sprog, der har dem, og b) du kan tåle omkostningerne (undtagelseshåndtering har en overhead. ) Det vil sige, at brug af
finally
kun er gyldigt under disse betingelser. Der er meget sjældne, men alligevel gyldige situationer, hvor en goto er vejen at gå. - Okay mennesker … hvad pokker er forskellen mellem
break 3
ellerbreak myLabel
oggoto myLabel
. Åh, ‘ er lige nøgleordet. Hvis du brugerbreak
,continue
eller et lignende søgeord, er du infact ved hjælp af engoto
(Hvis du brugerfor, while, foreach, do/loop
bruger du en betinget goto.) - Om ydeevne på lavt niveau – den moderne processors opførsel kan være svært at forudsige (pipeline, udførelse uden for ordre) så sandsynligvis i 99% af tilfældene er det ikke det værd, eller det kan endda være langsommere. @MatthewWhited: Scoping. Hvis du indtaster omfanget på et vilkårligt tidspunkt, er det ikke klart (for mennesket), hvad konstruktører skal kaldes (problemet findes også i C).
Svar
Styringskonstruktioner på højere niveau har tendens til at svare til begreber i problemdomænet. En if / else er en beslutning baseret på en eller anden betingelse. En løkke siger at udføre nogle handlinger gentagne gange. Selv en pause erklæring siger “vi gjorde dette gentagne gange, men nu er vi nødt til at stoppe”.
En goto-erklæring derimod har tendens til at svare til et koncept i det kørende program, ikke i problem domæne. Det siger at fortsætte udførelsen på et specificeret punkt i programmet . En person, der læser koden, skal udlede hvad det betyder med hensyn til problemdomænet.
Selvfølgelig kan alle konstruktioner på højere niveau defineres i form af gotos og enkle betingede grene . Det betyder ikke, at de bare er i forklædning. Tænk på dem som begrænsede gotos – og det er de begrænsninger, der gør dem nyttige. En pauseerklæring implementeres som et spring til slutningen af den lukkende sløjfe, men det er bedre tænkt som fungerer på sløjfen som helhed.
Alt andet lige er kode, hvis struktur afspejler den for problemdomænet, tendens til at være lettere at læse og vedligeholde.
Der er ingen tilfælde, hvor en goto-erklæring er absolut påkrævet (der er “s en sætning ), men der er tilfælde, hvor det kan være den mindst dårlige løsning. Disse tilfælde varierer fra sprog til sprog, afhængigt af hvilke højere konstruktioner sproget understøtter.
I C, for eksempel, mener jeg, at der er tre grundlæggende scenarier, hvor en goto er passende.
- Bryder ud af en indlejret sløjfe. Dette ville være unødvendigt, hvis sproget havde en mærket pauseerklæring.
- Redning af en strækning af kode (typisk en funktionsdel) i tilfælde af en fejl eller anden uventet begivenhed . Dette ville være unødvendigt, hvis sproget havde undtagelser.
- Implementering af en eksplicit endelig statsmaskine. I dette tilfælde (og jeg tror kun i dette tilfælde) svarer en goto direkte til et koncept i problemdomænet, der overgår fra en tilstand til en specificeret anden tilstand, hvor den aktuelle tilstand er repræsenteret af hvilken blok kode der i øjeblikket udføres .
På den anden side kan en eksplicit endelig tilstandsmaskine også implementeres med en switch-sætning inde i en loop. Dette har den fordel, at hver tilstand starter på samme sted i koden, hvilket f.eks. Kan være nyttigt til fejlfinding.
Hovedanvendelsen af en goto på et rimeligt moderne sprog (en, der understøtter, hvis / andet og sløjfer) er at simulere en kontrolflowkonstruktion, der mangler i sproget.
Kommentarer
- Dette er faktisk det bedste svar hidtil – ret overraskende, for et spørgsmål, der er halvandet år gammelt. 🙂
- +1 til ” hidtil bedste svar “. — ” Hovedanvendelsen af en goto på et rimeligt moderne sprog (en der understøtter hvis / ellers og sløjfer) er at simulere et kontrolflow konstruer, at ‘ mangler fra sproget. ”
- I switch-statement state machine, hver skriv til kontrolværdi er virkelig en
goto
. SSSM ‘ s er ofte gode strukturer at bruge, da de ser parater SM-tilstanden fra udførelseskonstruktionen, men de eliminerer ‘ t virkelig ” gotos “. - ” Alt andet lige er kode, hvis struktur afspejler problemdomænet, tendens til at være lettere at læse og vedligeholde. ” Jeg ‘ har længe vidst dette fuldstændigt, men manglede ordene til så præcist at kommunikere det på en måde, som andre programmører kan og vil faktisk forstå. Tak for dette.
- ” struktureret program sætning ” morer mig, da det har tendens til tydeligt at demonstrere påpege, at brug af strukturerede programmeringsudsagn til at efterligne en goto er meget mindre læselig end bare at bruge en goto!
Svar
Det afhænger helt sikkert af programmeringssprog. Hovedårsagen til, at goto
har været kontroversiel, er på grund af de dårlige virkninger, der opstår, når kompilatoren lader dig bruge det for liberalt. Problemer kan f.eks. Opstå, hvis det giver dig mulighed for at bruge goto
på en sådan måde, at du nu kan få adgang til en uinitialiseret variabel, eller værre, til at hoppe ind i en anden metode og rod med opkaldet stak. Det bør være kompilatorens ansvar at afvise meningsløs kontrolflow.
Java har forsøgt at “løse” dette problem ved helt at afvise goto
. Men Java giver dig mulighed for at bruge return
inde i en finally
-blok og dermed få en undtagelse til at blive slugt utilsigtet.Det samme problem er der stadig: Compileren udfører ikke sit job. Fjernelse af goto
fra sproget har ikke rettet det.
I C # er goto
lige så sikkert som break
, continue
, try/catch/finally
og return
. Det lader dig ikke bruge uinitialiserede variabler, det lader dig ikke hoppe ud af en endelig blok osv. Compileren klager. Dette skyldes, at det løser det virkelige problem, hvilket er som jeg sagde meningsløs kontrolflow. goto
annullerer ikke en bestemt tildelingsanalyse og andre rimelige compiler-kontroller på magisk vis.
Kommentarer
- Dit punkt er, at C # ‘ s
goto
ikke er ondt? I så fald er det tilfældet for ethvert rutinemæssigt brugt moderne sprog med engoto
-konstruktion, ikke kun C # …
Svar
Ja. Når dine sløjfer er indlejrede flere niveauer dybt, er goto
den eneste måde at elegant bryde ud af en indre sløjfe. Den anden mulighed er at indstille et flag og bryde ud af hver løkke, hvis dette flag opfylder en betingelse. Dette er virkelig grimt og ret fejlbehæftet. I disse tilfælde er goto
simpelthen bedre.
Selvfølgelig gør Javas mærkning break
udsagn det samme ting, men uden at tillade dig at springe til et vilkårligt punkt i koden, som løser problemet pænt uden at tillade de ting, der gør goto
onde.
Kommentarer
- goto er aldrig et elegant svar. Når dine sløjfer er indlejrede flere niveauer dybt, er dit problem, at du ikke har arkitekteret din kode for at undgå de multinestede sløjfer. Procedureopkald er IKKE fjenden. (Læs ” Lambda: The Ultimate … ” papirer.) Brug af en goto til at bryde ud af sløjfer indlejrede flere niveauer dybt er at lægge et plaster på en åben multipel brud: det kan være simpelt, men det er ikke ‘ t det rigtige svar.
- Og selvfølgelig er der er aldrig det ulige tilfælde, når der kræves dybt nestede sløjfer? At være en god programmør er ikke t bare om at følge reglerne, men også om at vide, hvornår de skal brydes.
- @ JohnR.Strohm Sig aldrig aldrig. Hvis du bruger udtryk som ” aldrig ” i programmeringen, har du ‘ klart ikke behandlet med hjørnesager, optimering, ressourcebegrænsninger osv. I dybt nestede sløjfer er goto virkelig den mest reneste, elegante måde at afslutte sløjferne på. Betyder ‘ ikke noget, hvor meget du ‘ har omformuleret din kode.
- @ JohnR.Strohm: Anden mest savnede funktion ved skift fra VB.NET til C #:
Do
-sløjfen. Hvorfor? Fordi jeg kan ændre den ene sløjfe, der har brug for en dyb pause i enDo
-sløjfe og skriveExit Do
og der ‘ er nejGoTo
. Indlejrede sløjfer sker hele tiden. At bryde stakken sker noget% af tiden. - @ JohnR.Strohm Den eneste grund til, at du siger ” goto er aldrig et elegant svar ” er fordi du besluttede dig for, at goto aldrig er et elegant svar, og derfor kan enhver løsning ved hjælp af goto ikke være et elegant svar.
Svar
Det meste af modløsheden kommer fra en slags “religion”, der er skabt over Gud Djikstra, der var overbevisende i de tidlige “60ere om den” vilkårlige magt til :
- spring et vilkårligt sted ind i en hvilken som helst blok kode
- -funktion, der ikke udføres fra begyndelsen
- sløjfer, der ikke er udført fra starten
- initialiseret oversprunget variabel
- spring væk fra en hvilken som helst blok kode uden nogen mulig oprydning.
Dette har ikke mere at gøre med goto
udsagn om de moderne sprog, hvis eksistens kun skyldes støtte til cr fratagelse af andre kodestrukturer end de sprog, der er angivet.
Især er det første hovedpunkt ovenfor tilladt længere, og det andet renses (hvis du goto
ude en blok stakken er viklet ordentligt ud, og alle korrekte destruktører kaldes)
Du kan henvise til dette svar for at få en idé om, hvordan selv kode ikke Brug af goto kan være ulæseligt. Problemet er ikke at gå i sig selv, men den dårlige brug af det.
Jeg kan skrive et helt program uden at bruge if
, bare for
. Selvfølgelig vil det ikke være godt læsbart, et klodset og unødigt kompliceret udseende.
Men problemet er ikke for
. Det er mig.
Ting som break
, continue
, throw
, bool needed=true; while(needed) {...}
osv. bemærker mere end maskerade goto
for at flygte væk fra scimitars af Djikstrarian nidkærere, at – 50 år efter opfindelsen af moderne sprog – ønsker stadig deres fanger. De glemte, hvad Djikstra talte om, de husker kun titlen på hans note (GOTO betragtes som skadelig, og det var ikke engang hans onw-titel: den blev ændret af redaktøren) og skyld og bash, bash og skyld hver konstruktion, der har disse 4 bogstav placeret i rækkefølge.
Det er 2011: det er tid til at forstå, at goto
ikke har noget at gøre med GOTO
udsagn, som Djikstra overbeviste.
Kommentarer
- ” Ting som pause, fortsæt , kast, bool nødvendig = sand; mens (nødvendigt) {…} osv. bemærker mere end maskerade til ” Det er jeg ikke ‘. Jeg foretrækker, at ” ting som pause osv. Er begrænset til “, eller noget lignende. Det største problem med goto er, at det normalt er for stærkt. I det omfang den nuværende goto er mindre magtfuld end Dijkstra ‘ s, er dit svar fint med mig.
- @ MuhammadAlkarouri: Jeg er helt enig. Du har lige fundet en bedre ordlyd til at udtrykke nøjagtigt mit koncept. Mit pointe er, at disse begrænsninger undertiden ikke kan finde anvendelse, og den slags begrænsning, du har brug for, ikke findes på sproget. Derefter er en mere ” kraftfuld ” ting, mindre specialiseret, hvad der gør dig i stand til at løse. For eksempel er Java
break n
ikke tilgængelig i C ++, derforgoto escape
, selvomescape
kræves ikke at være lige uden for n-ple-sløjfen.
Svar
Den ulige goto her eller der, så længe det er lokalt for en funktion, sjældent skader læsbarheden væsentligt. Det gavner det ofte ved at henlede opmærksomheden på, at der er noget usædvanligt i denne kode, der kræver brug af en noget usædvanlig kontrolstruktur .
Hvis (lokale) fotos skader læsbarheden betydeligt, er det normalt et tegn på, at funktionen, der indeholder goto, er blevet for kompleks.
Den sidste goto, jeg satte i en stykke C-kode var at opbygge et par sammenkoblede sløjfer. Det passer ikke ind i den normale definition af “acceptabel” anvendelse af goto, men funktionen endte betydeligt mindre og klarere som et resultat. For at undgå goto ville have krævet en særlig rodet overtrædelse af DRY.
Kommentarer
- Svaret på dette er mest pithy angivet i den gamle ” Læg ‘ s Kartoffelchips ” slogan: ” Bet du kan ‘ ikke spiser en “. I dit eksempel har du to ” sammenlåsende ” (uanset hvad det betyder, og jeg ‘ m vedder på, at det ikke er ‘ t smukke) sløjfer, og den goto gav dig en billig ud. Hvad med vedligeholdelses fyren, der skal ændre koden, efter at du er ramt af en bus? Kommer goto at gøre hans liv lettere eller sværere? Har disse to sløjfer brug for en ny overvejelse?
Svar
Jeg tror, at hele dette spørgsmål har været et tilfælde af gøen det forkerte træ.
GOTO som sådan virker ikke problematisk for mig, men snarere er det meget ofte et symptom på en faktisk synd: spaghetti-kode.
Hvis GOTO forårsager større krydsning af flowkontrollinjer, så er det dårligt, punktum. Hvis det ikke krydser nogen flowkontrollinjer, er det harmløst. I den grå zone imellem har vi ting som loop-bailouts, der er stadig nogle sprog, der ikke har tilføjet konstruktioner, der dækker alle de legitime grå sager.
Det eneste tilfælde, jeg faktisk har brugt det i mange år er tilfældet med sløjfen, hvor beslutningspunktet er midt i sløjfen. Du er tilbage med enten duplikeret kode, et flag eller en GOTO. Jeg finder GOTO-løsningen den bedste af de tre. Der er ingen krydsning af flowkontrollinjer her, den er harmløs.
Kommentarer
- Sagen, du henviser til, kaldes undertiden “loop and a half” eller “N plus one half loop”, og det er en berømt brugssag til
goto
s, der hopper ind i en løkke (hvis sproget tillader dette; da det andet tilfælde er at springe ud af sløjfen i midten, er det som regel trivielt udengoto
- (Ak, de fleste sprog forbyder at hoppe ind i en løkke.)
- @KonradRudolph: Hvis du implementerer ” loop ” med GOTO er der ingen anden loopstruktur at hoppe ind i.
- Jeg tænker på
goto
som at råbe KONTROLFLOWEN HER GØR ‘ T FIT NORMAL STRUKTURERET-PROGRAMMERING MØNSTER . Da kontrolstrømme, der passer til strukturerede programmeringsmønstre, er nemmere at begrunde end dem, der ikke ‘ t, bør man forsøge at bruge sådanne mønstre, når det er muligt; hvis kode ikke passer til sådanne mønstre, bør man ikke ‘ t råbe, at den ikke ‘ t. På den anden side, i tilfælde hvor koden virkelig ikke ‘ ikke passer til sådanne mønstre, kan det være bedre at råbe om det end at lade koden passe, når det virkelig ikke ‘ t. - @supercat Nå, forestil dig, at du skrev dig selv en tidsplan, og så blæser vinden den ud af dine hænder. I henhold til din logik skal du ikke ‘ ikke hente det, fordi jagten efter din tidsplan ikke var ‘ t på din tidsplan.
Svar
Ja, den goto kan bruges til at gavne udviklerens oplevelse: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/
Men ligesom med ethvert kraftfuldt værktøj (pekere, flere arv osv.) skal man være disciplineret bruger det. Eksemplet i linket bruger PHP, som begrænser brugen af goto-konstruktionen til den samme funktion / metode og deaktiverer muligheden for at springe ind i en ny kontrolblok (f.eks. Loop, switch statement osv.)
Svar
Afhænger af sproget. Det bruges f.eks. Stadig meget i Cobol-programmering. Jeg har også arbejdet på en Barionet 50-enhed, hvis firmwareprogrammeringssprog er en tidlig BASIC-dialekt, der naturligvis kræver, at du bruger Goto.
Svar
goto
kan være nyttigt, når du overfører ældre samlekode til C. I første omgang er en instruktions- by-instruktionskonvertering til C, ved hjælp af goto
som erstatning for montøren “s branch
instruktion, kan muliggøre meget hurtig portering.
Kommentarer
- Korrekt, men et af argumenterne mod
goto
s er, at de modvirker kompilatoroptimeringer. - @Sapphire_Brick: Mange kompilatoroptimeringer er designet omkring bestemte eksekveringsmønstre. Hvis opgaven, der skal udføres, ikke ‘ ikke passer til de understøttede eksekveringsmønstre, ” modvirkning af ” optimeringer muligvis ikke være en dårlig ting.
Svar
Jeg vil argumentere nej. De bør altid erstattes med et værktøj, der er mere specifikt for det problem, gotoen bruges til at løse (medmindre det ikke er tilgængeligt på dit sprog). F.eks. Bryder udsagn og undtagelser til tidligere goto-løste problemer med sløjfe undslippe og fejlhåndtering.
Kommentarer
- I ‘ d hævder, at når sprog har begge disse funktioner er
goto
typisk fraværende fra disse sprog. - Men er det fordi de ikke ‘ t har brug for dem, eller fordi mennesker mener, at de ikke ‘ ikke har brug for dem?
- Dine synspunkter er store. Der er mange tilfælde, når
goto
er den tætteste ting ved selve problemdomænet semantik, alt andet ville være et beskidt hack. - @ SK-logik: Jeg don ‘ tænk ikke ordet ” bigoted ” betyder hvad du synes det betyder.
- @Keith,
intolerant helliget sine egne meninger og fordomme ” – at ‘ er hvad jeg følg konsekvent her med dette goto-bashing bind for øjnene. ” Skal altid udskiftes ” er fanatiske ‘ s ord, i det mindste. Intet tæt på en ordentlig, sund mening, men bare en ren afsky. Denne ” altid ” giver ikke plads til nogen alternativ mening, se?
Svar
Jeg vil sige nej. Hvis du finder behovet for at bruge GOTO, vil jeg vædde på, at der er et behov for at redesigne koden.
Kommentarer
- Måske, men du haven ‘ t gav nogen ræsonnement
- Dijkstra leverede ræsonnementet detaljeret for årtier siden.
- Just Dogma. Ingen resoner. Bemærk: Djikstra er IKKE EN GÆLDENERE RESON: det henviste til BASIC- eller FORTRAN GOTO-erklæringen fra den tidlige ‘ 60erne. De har intet at gøre med de virkelig anæmiske (sammenlignet med kraften i disse) gots-s i dag.
- @EmilioGaravaglia Nå, den del af hans ræsonnement, der stadig gælder i dag, er, at det ‘ er meget let at skrive spaghettikode ved at bruge måde til mange fotos. Efter denne logik bør vi dog ikke ‘ ikke bruge pegepinde, fordi brug af så mange pegepinde som
number of gotos needed to create problems
ville skabe lignende kaos.
goto
er, hvad CPUen i sidste ende gør, men det fungerer ikke godt med, hvad mennesker har brug for at forstå og abstrakte, fordi der ikke er noget mærke på målet ende. Sammenlign med IntercalCOMEFROM
.goto
ikke påkrævet. Det er bare den mest rationelle måde at implementere dem på de tvingende sprog, da det er den nærmeste ting til selve semantikken ved statsovergangen. Og dens destination kan være ret langt fra kilden, den vinder ‘ t hindrer læsbarheden. Mit foretrukne eksempel på en sådan kode er D.E. Knuth ‘ s implementering af Adventure-spillet.