Mengapa Go memiliki pernyataan “goto”

110

Saya terkejut saat mengetahui bahwa Go memiliki pernyataan 'goto' . Saya selalu diajari bahwa pernyataan 'goto' adalah sesuatu dari masa lalu dan kejahatan karena hal itu menghalangi aliran program yang sebenarnya, dan bahwa fungsi atau metode selalu merupakan cara yang lebih baik untuk mengendalikan aliran.

Saya pasti melewatkan sesuatu. Mengapa Google memasukkannya?

membahayakan
sumber
5
Ada kalanya Anda benar-benar membutuhkan pernyataan goto. Goto adalah jahat hanya jika digunakan tanpa pandang bulu. Misalnya, jika sangat sulit, jika bukan tidak mungkin, untuk menulis parser mesin status Hingga tanpa pernyataan goto.
xbonez
5
Ini tidak spesifik untuk Go, tetapi untuk diskusi yang baik tentang mengapa bahasa mempertahankan pernyataan tersebut, dan untuk melihat argumen yang menentang penggunaannya, lihat posting ini . Ada beberapa referensi bagus yang ditautkan dalam pertanyaan. Edit: inilah yang lainnya .
Cᴏʀʏ
3
Untuk menyelamatkan OP dari grepping melalui diskusi SO yang disediakan, berikut adalah pembahasan LKML yang cukup banyak merangkum mengapa gotoberguna dalam kasus-kasus tertentu. Baca setelah mempelajari jawaban @ Kissaki.
kostix
1
Terkait: programmer.stackexchange.com/q/566/33478 (dan lihat jawaban saya ).
Keith Thompson
Ini berguna untuk menerapkan pola kelanjutan, di mana Anda menyimpan dari tumpukan kemudian kembali ke tempat Anda saat Anda ingin melanjutkan.
Justin Dennahower

Jawaban:

78

Ketika kami benar-benar memeriksa kode sumber pustaka standar Go, kami dapat melihat di mana gotosebenarnya diterapkan dengan baik.

Sebagai contoh, dalam math/gamma.goberkas, yang gotopernyataan digunakan :

  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)
}

Dalam gotokasus ini, kita tidak perlu memasukkan variabel lain (boolean) yang digunakan hanya untuk aliran kontrol, diperiksa di bagian akhir. Dalam hal ini , gotopernyataan tersebut membuat kode sebenarnya lebih baik untuk dibaca dan lebih mudah diikuti (sangat bertentangan dengan argumen yang menentang yang gotoAnda sebutkan).

Perhatikan juga, bahwa gotopernyataan tersebut memiliki kasus penggunaan yang sangat spesifik. The spesifikasi bahasa di goto menyatakan bahwa hal itu mungkin tidak melompati variabel yang masuk ke lingkup (yang dinyatakan), dan mungkin tidak melompat ke blok lainnya (kode-).

Kissaki
sumber
69
Dalam contoh Anda, mengapa tidak memperkenalkan fungsi small(x,z)untuk dipanggil saja? Dengan begitu kita tidak perlu memikirkan variabel apa saja yang bisa diakses di small:label. Saya menduga alasannya pergi masih kekurangan jenis dukungan sebaris tertentu di kompiler.
Thomas Ahle
5
@ Jessta: Untuk itulah kami memiliki visibilitas dan ruang lingkup, bukan?
Thomas Ahle
6
@ThomasAhle Go tidak mengizinkan gotountuk menunjuk ke label setelah variabel baru dimasukkan. Menjalankan pernyataan "goto" tidak boleh menyebabkan variabel apa pun masuk ke cakupan yang belum ada dalam cakupan pada titik goto.
km6zla
4
@ ogc-nick Maaf saya tidak jelas, maksud saya fungsi dapat dideklarasikan dalam lingkup di mana mereka dibutuhkan, jadi mereka tidak terlihat oleh kode yang tidak membutuhkannya. Saya tidak berbicara tentang goto's dan scope.
Thomas Ahle
4
@MosheRevah Kode yang direferensikan tidak dioptimalkan untuk keterbacaan. Ini dioptimalkan untuk kinerja mentah, menggunakan goto yang mencakup 22 baris dalam satu fungsi. (Dan lamaran Thomas Ahle bahkan lebih mudah dibaca oleh mata saya.)
joel.neely
30

Goto adalah ide yang bagus jika tidak ada fitur kontrol bawaan yang melakukan apa yang Anda inginkan, dan saat Anda dapat mengekspresikan apa yang Anda inginkan dengan goto. (Sayang sekali dalam kasus ini dalam beberapa bahasa ketika Anda tidak memiliki goto. Anda akhirnya menyalahgunakan beberapa fitur kontrol, menggunakan bendera boolean, atau menggunakan solusi lain yang lebih buruk daripada goto.)

Jika beberapa fitur kontrol lain (digunakan dengan cara yang cukup jelas) dapat melakukan apa yang Anda inginkan, Anda harus menggunakannya sebagai preferensi untuk pergi. Jika tidak, berani dan gunakan goto!

Terakhir, perlu dicatat bahwa Go's goto memiliki beberapa batasan yang dirancang untuk menghindari beberapa bug yang tidak jelas. Lihat batasan ini di spesifikasi.

Sonia
sumber
7

Pernyataan Goto telah menerima banyak diskredit sejak era kode Spaghetti di tahun 60an dan 70an. Saat itu, metodologi pengembangan perangkat lunak sangat miskin atau bahkan tidak ada sama sekali. Namun Goto sebenarnya tidak jahat tetapi tentu saja dapat disalahgunakan dan disalahgunakan oleh pemrogram yang malas atau tidak terampil. Banyak masalah dengan Gotos yang disalahgunakan dapat diselesaikan dengan proses pengembangan seperti tinjauan kode tim.

gotoadalah lompatan dengan cara teknis yang sama seperti continue, breakdan return. Seseorang dapat berargumen bahwa ini adalah pernyataan jahat dengan cara yang sama tetapi sebenarnya tidak.

Mengapa tim Go menyertakan Gotos mungkin karena fakta bahwa ini adalah kontrol aliran primitif yang umum. Selain itu, mereka berharap dapat menyimpulkan bahwa cakupan Go tidak termasuk membuat bahasa yang aman bagi orang bodoh tidak mungkin untuk disalahgunakan.

Gustav
sumber
continue,, breakdan returnsangat berbeda dalam satu kunci khusus: mereka hanya menetapkan "keluar dari lingkup pelingkup". Mereka tidak hanya mendorong tetapi secara eksplisit mengharuskan pengembang mempertimbangkan struktur kode mereka dan mengandalkan primitif pemrograman terstruktur (untuk loop, fungsi, dan pernyataan sakelar). Satu-satunya anugrah gotopernyataan adalah bahwa mereka memungkinkan Anda menulis rakitan di HLL ketika pengoptimal kompiler tidak sesuai dengan tugasnya, tetapi ini datang dengan biaya keterbacaan dan pemeliharaan.
Parthian Shot
Alasan ini begitu mengejutkan untuk menemukan di mana adalah bahwa, dalam setiap kasus lain di mana para pengembang golang memiliki pilihan antara paradigma pemrograman terstruktur dan "kontrol aliran yang luar biasa" / manipulasi instruksi pointer seperti setjmp, longjmp, goto, dan try / except / finallymereka memilih untuk err di samping hati-hati. goto, fwict, adalah satu-satunya persetujuan untuk aliran kontrol pra- "pemrograman terstruktur".
Parthian Shot