it-swarm-eu.dev

Je použití goto někdy užitečné?

goto je téměř všeobecně odrazován. Je použití tohoto prohlášení někdy užitečné?

30
Casebash

Toto bylo několikrát diskutováno na Stack Overflow a Chris Gillum shrnuto možné použití goto :

Čistě opouští funkci

Ve funkci můžete často přidělit zdroje a je třeba ukončit na více místech. Programátoři mohou svůj kód zjednodušit tím, že na konec funkce umístí kód vyčištění zdroje všechny všechny „výstupní body“ funkce by vyškrtly štítek vyčištění. Tímto způsobem nemusíte psát čisticí kód v každém „koncovém bodě“ funkce.

Ukončení vnořených smyček

Pokud jste ve vnořené smyčce a potřebujete vytrhnout smyčky vše, může goto udělat mnohem čistší a jednodušší než příkazy break a if-kontroluje.

Vylepšení výkonu na nízké úrovni

Platí to pouze v kódu, který je kritický pro perf, ale příkazy goto se provádějí velmi rychle a mohou vám poskytnout podporu při pohybu funkcí. Toto je však dvojsečný meč, protože kompilátor obvykle nemůže optimalizovat kód, který obsahuje gotos.

Tvrdil bych, jak mnozí jiní tvrdí, že ve všech těchto případech je použití goto používáno jako prostředek, jak se dostat ven z rohu, do kterého se kóduje, a je to obvykle příznak kódu to by mohlo být refactored.

51
user8

Konstrukty toku vyšších úrovní mají tendenci odpovídat konceptům v problémové doméně. If/else je rozhodnutí založené na nějaké podmínce. Smyčka říká, že nějakou akci provádí opakovaně. Dokonce i prohlášení o přerušení říká: „Dělali jsme to opakovaně, ale nyní musíme přestat“.

Naproti tomu příkaz goto odpovídá spíše konceptu v běžícím programu, nikoli v problémové oblasti. Říká se, že bude pokračovat v provádění ve specifikovaném bodě v programu . Někdo, kdo čte kód, musí usoudit , co to znamená s ohledem na problémovou doménu.

Samozřejmě všechny konstrukty vyšší úrovně mohou být definovány z hlediska goto a jednoduchých podmíněných větví. To neznamená, že jsou pouze převleky za goto. Přemýšlejte o nich jako o omezených gotos - a právě tato omezení je činí užitečnými. Příkaz break je implementován jako skok na konec ohraničující smyčky, ale je lepší myslet na to, že pracuje na smyčce jako celku.

Pokud jsou všechny ostatní stejné, kód, jehož struktura odráží strukturu problémové domény, je snazší přečíst a udržovat.

Neexistují žádné případy, kdy je nezbytně nutné goto prohlášení (existuje věta v tomto smyslu), ale existují případy, kdy to může být nejméně špatné řešení. Tyto případy se liší od jazyka k jazyku, v závislosti na tom, co vyšší úroveň vytváří jazyk, který jazyk podporuje.

Například v C se domnívám, že existují tři základní scénáře, ve kterých je vhodné použít goto.

  1. Vypukne z vnořené smyčky. To by bylo zbytečné, pokud by jazyk měl označené prohlášení o přerušení.
  2. Poskytování záchranných služeb z úseku kódu (obvykle funkčního těla) v případě chyby nebo jiné neočekávané události. To by bylo zbytečné, pokud by jazyk měl výjimky.
  3. Implementace explicitního stavového automatu. V tomto případě (a myslím si, že pouze v tomto případě) goto odpovídá přímo konceptu v problémové doméně, přechází z jednoho stavu do specifikovaného jiného stavu, kde aktuální stav je reprezentován tím, který blok kódu právě provádí. .

Na druhé straně lze stroj explicitního konečného stavu implementovat také s příkazem switch uvnitř smyčky. To má tu výhodu, že každý stav začíná na stejném místě v kódu, což může být užitečné například pro ladění.

Hlavní použití goto v přiměřeně moderním jazyce (jazyk, který podporuje if/else a loop) je simulovat konstrukci řídícího toku, která v jazyce chybí.

46
Keith Thompson

Určitě to záleží na programovacím jazyce. Hlavní důvod goto byl kontroverzní, je kvůli jeho nepříznivým účinkům, ke kterým dochází, když vám kompilátor umožňuje používat ho příliš liberálně. Problémy mohou nastat například tehdy, pokud vám umožní použít goto takovým způsobem, že nyní můžete přistupovat k neinicializované proměnné nebo ještě horší, přeskočit na jinou metodu a nepořádek s hromadou hovorů. Kompilátor by měl zakázat nesmyslný kontrolní tok.

Java se pokusila tento problém „vyřešit“ tím, že zcela zakázala goto. Nicméně, Java umožňuje použít return uvnitř bloku finally a způsobit tak neúmyslné spolknutí výjimky. Stejný problém stále existuje: kompilátor je Odebrání goto z jazyka jej neopravilo.

V C # je goto stejně bezpečné jako break, continue, try/catch/finally a return. Nedovolí vám použít neinicializované proměnné, nedovolí vám vyskočit z posledního bloku atd. Kompilátor si bude stěžovat. Je to proto, že řeší problém skutečný, což je, jako jsem řekl, nesmyslný řídicí tok. goto magicky nezruší analýzu definitivního přiřazení a další přiměřené kontroly kompilátoru.

11
Timwi

Ano. Když jsou vaše smyčky vnořeny do několika úrovní, je gotopouze způsob, jak elegantně vypuknout z vnitřní smyčky. Druhou možností je nastavit příznak a vyřadit z každé smyčky, pokud tento příznak splňuje podmínku. To je opravdu ošklivé a docela náchylné k chybám. V těchto případech je goto prostě lepší.

Samozřejmě, Java označený příkaz break dělá to samé, ale bez toho, aby vám umožnil skočit na libovolný bod v kódu, což problém řeší úhledně, aniž by to umožňovalo věci, které způsobují zlo goto.

9
Chinmay Kanchi

Většina odradění přichází z jakési „náboženství“, které bylo vytvořeno bohem Djikstrem, který na počátku 60. let přesvědčoval o tom, že je bez rozdílu moc:

  • skočit kamkoli do libovolného bloku kódu
    • funkce nebyla od začátku vykonána
    • smyčky nebyly provedeny od začátku
    • přeskočení inicializace proměnné
  • skok pryč z jakéhokoli bloku kódu bez jakéhokoli možného vyčištění.

Toto nemá nic společného s příkazem goto moderních jazyků, jehož existence je pouze kvůli podpoře vytváření struktur kódů jiných, než jsou jazyky poskytované jazykem.

Zejména první hlavní bod výše je již povolen a druhý je vyčištěn (pokud goto z bloku se zásobník řádně uvolní a zavolají se všechny správné destruktory)

Můžete poslat tato odpověď , abyste získali představu o tom, jak může být nečitelný i kód nepoužívající goto. Problém není sám o sobě, ale špatné použití.

Dokážu napsat celý program bez použití if, pouze for. Samozřejmě to nebude dobře čitelné, neohrabané a zbytečně komplikované.

Problém však není for. To jsem já.

Věci jako break, continue, throw, bool needed=true; while(needed) {...} atd. Si všimnou více než maškaráda goto k útěku ze scimitářů djikstrariánských fanatiků, kteří - 50 let po vynálezu moderních jazyků - stále chtějí své vězně. Zapomněli o tom, o čem Djikstra mluvil, pamatují si pouze název své poznámky (GOTO považován za škodlivý, a nebyl to ani jeho první titul: změnil jej editor) a vinu a bash, bash a vinu za každý rozpor s těmito 4 dopis umístěn v pořadí.

Je rok 2011: je čas pochopit, že goto se nezabývá příkazem GOTO, o kterém Djikstra přesvědčoval.

7

Podivné goto sem nebo tam, pokud je to místní funkce, málokdy významně poškozuje čitelnost. Často to prospívá tím, že upozorňuje na skutečnost, že v tomto kódu se děje něco neobvyklého, které vyžaduje použití poněkud neobvyklé řídicí struktury.

Pokud (místní) goto značně poškozují čitelnost, pak je obvykle známkou, že funkce obsahující goto je příliš složitá.

Posledním krokem, který jsem vložil do kusu kódu C, bylo sestavení dvojice vzájemně propojených smyček. Nesedí do normální definice „přijatelného“ použití goto, ale funkce nakonec skončila výrazně menší a jasnější. Abychom se vyhnuli goto, vyžadovalo by to zvlášť chaotické porušení DRY.

4
blucz

Myslím, že celý tento problém byl případem štěkání nesprávného stromu.

GOTO jako taková se mi nezdá problematická, ale spíše je to příznak skutečného hříchu: špagetový kód.

Pokud GOTO způsobí významné křížení vedení pro řízení toku, pak je to špatné období. Pokud nepřekročí žádné linie řízení toku, je to neškodné. V šedé zóně mezi tím máme věci jako bailouts smyčky, stále existují některé jazyky, které nepřidaly konstrukty, které pokrývají všechny legitimní šedé případy.

Jediným případem, který jsem zjistil, že ho skutečně používám po mnoho let, je případ smyčky, kde je rozhodovací bod uprostřed smyčky. Zůstane vám duplicitní kód, příznak nebo GOTO. Řešení GOTO považuji za nejlepší ze tří. Zde nedochází k žádnému křížení vedení pro řízení toku, je to neškodné.

3
Loren Pechtel

Ano, goto lze využít ke zkušenostem vývojáře: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Stejně jako u každého mocného nástroje (ukazatele, vícenásobná dědičnost atd.) Je však třeba jej disciplinovat. Příklad uvedený v odkazu používá PHP, které omezuje použití goto konstruktu na stejnou funkci/metodu a znemožňuje schopnost skočit do nového řídícího bloku (např. Smyčka, příkaz switch atd.)

1
AdamJonR

Závisí na jazyce. Je to stále široce používané například v programování Cobol. Také jsem pracoval na zařízení Barionet 50, jehož programovací jazyk firmwaru je raný základní dialekt, který samozřejmě vyžaduje použití Goto.

1
user16764

Řekl bych ne. Pokud zjistíte, že je třeba používat GOTO, vsadím se, že je třeba přepracovat kód.

0
Walter

goto může být užitečné při přenesení staršího kódu assembleru na C. V první instanci převod instrukce po instrukci na C, pomocí goto jako náhrada za branch instrukce, může umožnit velmi rychlé portování.

0
Graham Borland