Чому Go має заяву "goto"


110

Я був здивований, виявивши, що у Go є заява "goto" . Мене завжди вчили, що "goto" твердження - це минуле і зло, оскільки воно замикає фактичний потік програми, і що функції або методи завжди є кращим способом контролю потоку.

Мені, мабуть, чогось не вистачає. Чому Google включив його?


5
Бувають випадки, коли вам дійсно потрібна операція goto. Гото є злими лише тоді, коли застосовується без розбору. Наприклад, якщо дуже важко, якщо не неможливо, написати Кінцевий автомат-аналізатор стану без goto заяв.
xbonez

5
Це не конкретно для Go, але для хорошої дискусії про те, чому мови зберігають заяву, і щоб побачити аргументи проти її використання, ознайомтеся з цим повідомленням . Є кілька хороших посилань, пов'язаних у питанні. Редагувати: ось ще одна .
Cᴏʀʏ

3
Щоб врятувати ОП від прихватування за допомогою обговорень SO, ось дискусія про LKML, яка в значній мірі резюмує, чому gotoце корисно в певних випадках. Прочитайте, вивчивши відповідь @ Кіссакі.
kostix


Корисно реалізувати шаблон продовження, коли ви зберігаєте стек, а потім повертаєтесь туди, де ви були, коли хочете відновити.
Джастін Деннахауер

Відповіді:


78

Коли ми перевіряємо вихідний код стандартної бібліотеки Go, ми можемо побачити, де gotos насправді добре застосовано.

Наприклад, у math/gamma.goфайлі використовується gotoоператор :

  for x < 0 {
    if x > -1e-09 {
      goto small
    }
    z = z / x
    x = x + 1
  }
  for x < 2 {
    if x < 1e-09 {
      goto small
    }
    z = z / x
    x = x + 1
  }

  if x == 2 {
    return z
  }

  x = x - 2
  p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6]
  q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7]
  return z * p / q

small:
  if x == 0 {
    return Inf(1)
  }
  return z / ((1 + Euler*x) * x)
}

У gotoцьому випадку нас рятує від введення ще однієї (булевої) змінної, яка використовується лише для контрольного потоку, перевіреного в кінці.В цьому випадку , то gotoоператор робить код на самом деле краще читати і легше подальшої (цілком на відміну від аргументу проти gotoви згадали).

Також зауважте, що ця gotoзаява має дуже специфічний випадок використання. Специфікація мови на goto повідомляє, що вона може не переходити через змінні, що надходять у область (декларується), і не може переходити в інші (кодові) блоки.


69
У вашому прикладі, чому б просто не запровадити функцію small(x,z)для виклику? Таким чином, нам не потрібно думати про те, які змінні доступні в small:етикетці. Я підозрюю, що причина у тому, що у компіляторі все ще бракує певних типів вбудованої підтримки.
Томас Але

5
@Jessta: Для цього ми маємо видимість і сферу, правда?
Thomas Ahle


4
@ ogc-nick Вибачте, мені не було зрозуміло, я мав на увазі, що функції можна оголосити в тій області, де вони потрібні, тому їх не видно коду, який їм не потрібен. Я не говорив про гото та сферу застосування.
Томас Ейл

4
@MosheRevah Посиланий код не оптимізований для читання. Оптимізовано для вихідної продуктивності за допомогою goto, який охоплює 22 рядки в межах однієї функції. (І пропозиція Томаса Ейла ще більше читається моєму оці.)
joel.neely

30

Goto - це гарна ідея, коли жодна з вбудованих функцій управління не робить те, що ви хочете, і коли ви можете висловити те, що ви хочете, за допомогою goto. (Соромно в цих випадках у деяких мовах, коли у вас немає goto. Ви, в кінцевому підсумку, зловживаєте деякою функцією управління, використовуючи булові прапори або використовуєте інші рішення, гірші, ніж goto.)

Якщо якась інша функція управління (використовується досить очевидно) може робити все, що завгодно, вам слід скористатися нею, щоб перейти до goto. Якщо ні, будьте сміливі та використовуйте goto!

Нарешті, варто відзначити, що goto Go має деякі обмеження, призначені для уникнення деяких незрозумілих помилок. Дивіться ці обмеження в специфікації.


7

Заяви Гото отримали багато дискредитації з епохи коду спагетті в 60-ті та 70-ті. Тоді ще не було жодної методики розробки програмного забезпечення. Однак Goto не є споконвічно злими, але, звичайно, їх можна зловживати і зловживати ледачими або некваліфікованими програмістами. Багато проблем із зловживанням Gotos можна вирішити за допомогою процесів розробки, таких як огляд коду команди.

gotoє стрибками в тому ж технічному порядку continue, що breakі return. Можна стверджувати, що ці заяви є злими однаково, але вони не є.

Чому команда Go включила Gotos, ймовірно, через те, що це загальний примітив управління потоком. Окрім того, вони сподіваються зробити висновок, що сфера використання Go виключає неможливість зловживати мовою, захищеною від ідіотів.


continue, breakІ returnдуже різні в один ключ зокрема: вони вказують тільки «покинути сферу огороджувальну». Вони не лише заохочують, але й прямо вимагають, щоб розробник розглядав структуру свого коду і покладався на структуровані примітивні програми (для циклів, функцій та операторів переключення). Єдине збереження витонченості gotoвисловлювань полягає в тому, що вони дозволяють писати збірку в HLL, коли оптимізатор компілятора не вирішує завдання, але це пов'язано з читабельністю та ремонтопридатністю.
Парфянський розстріл

Причина це так дивно , щоб знайти в дорозі, що, в будь-якому іншому випадку , коли розробники golang був вибір між структурованим програмуванням парадигмою і «винятковим контролем потоку» / покажчик інструкції Маніпуляції подобається setjmp, longjmp, gotoі try / except / finallyвони вирішило підстрахуватися на стороні обережності. goto, fwict, - це єдине згоду на керування потоком управління за "структурованим програмуванням".
Парфянський розстріл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.