Bu belirgin ve konuyla ilgili durumlar için kullanıldığında goto'nun nesi kötü?


40

Bunun gotokötü bir şey olduğunu her zaman biliyordum, bir bodrum katında, hiçbir zaman iyi görülmeyen bir yerde kilitliydi, ancak bugün kullanımı mükemmel bir kod örneği koydum goto.

IP listesinin içinde olup olmadığını kontrol etmem gereken bir IP'm var ve daha sonra koda devam edin, aksi takdirde bir istisna atayım.

<?php

$ip = '192.168.1.5';
$ips = [
    '192.168.1.3',
    '192.168.1.4',
    '192.168.1.5',
];

foreach ($ips as $i) {
    if ($ip === $i) {
        goto allowed;
    }
}

throw new Exception('Not allowed');

allowed:

...

Ben kullanmıyorsanız gotosonra ben gibi bazı değişken kullanmak zorunda

$allowed = false;

foreach ($ips as $i) {
    if ($ip === $i) {
        $allowed = true;
        break;
    }
}

if (!$allowed) {
    throw new Exception('Not allowed');
}

Benim sorum bu kadar gotobelirgin ve imo ilgili davalarda kullanıldığında neyin kötü olduğu ?


Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
maple_shaft

Yanıtlar:


120

GOTO kendi başına acil bir sorun değil, insanların onunla uygulama eğiliminde olduğu kapalı durum makineleri. Senin durumunda, IP adresinin izin verilen adresler listesinde olup olmadığını kontrol eden bir kod istiyorsun.

if (!contains($ips, $ip)) throw new Exception('Not allowed');

bu yüzden kodunuz bir durumu kontrol etmek istiyor. Bu kontrolü gerçekleştirecek algoritma burada endişe etmemelidir, ana programınızın zihinsel alanında kontrol atomiktir. Böyle olması gerekiyor.

Ancak kontrolü yapan kodu ana programınıza koyarsanız, onu kaybedersiniz. Değişken durumu, açıkça belirtin:

$list_contains_ip = undef;        # STATE: we don't know yet

foreach ($ips as $i) {
  if ($ip === $i) {
      $list_contains_ip = true;   # STATE: positive
      break;
  }
                                  # STATE: we still don't know yet, huh?                                                          
                                  # Well, then...
  $list_contains_ip = false;      # STATE: negative
}

if (!$list_contains_ip) {
  throw new Exception('Not allowed');
}

$list_contains_iptek durum değişkeniniz nerede , ya da dolaylı olarak:

                             # STATE: unknown
foreach ($ips as $i) {       # What are we checking here anyway?
  if ($ip === $i) {
    goto allowed;            # STATE: positive
  }
                             # STATE: unknown
}
                             # guess this means STATE: negative
throw new Exception('Not allowed');

allowed:                     # Guess we jumped over the trap door

Gördüğünüz gibi, GOTO yapısında bildirilmemiş bir durum değişkeni var. Bu başlı başına bir sorun değil, ancak bu değişkenler çakıl taşları gibidir: birini taşımak zor değildir, bunlarla dolu bir çanta taşımak sizi terletir. Kodunuz aynı kalmayacak: gelecek ay özel ve genel adresleri birbirinden ayırmanız istenecek. Bundan sonraki ay, kodunuzun IP aralıklarını desteklemesi gerekir. Gelecek yıl, birileri sizden IPv6 adreslerini desteklemenizi isteyecek. Kısa sürede kodunuz şöyle görünecek:

if ($ip =~ /:/) goto IP_V6;
if ($ip =~ /\//) goto IP_RANGE;
if ($ip =~ /^10\./) goto IP_IS_PRIVATE;

foreach ($ips as $i) { ... }

IP_IS_PRIVATE:
   foreach ($ip_priv as $i) { ... }

IP_V6:
   foreach ($ipv6 as $i) { ... }

IP_RANGE:
   # i don't even want to know how you'd implement that

ALLOWED:
   # Wait, is this code even correct?
   # There seems to be a bug in here.

Ve bu kodun hatalarını ayıklamak zorunda olanlar, sizi ve çocuklarınızı lanetleyecek.

Dijkstra şöyle koyar:

Go to ifadesinin dizginsiz kullanımı, sürecin ilerlemesini tanımlamak için anlamlı bir koordinat kümesi bulmanın çok zor hale gelmesinin hemen bir sonucudur.

Bu yüzden GOTO zararlı olarak kabul ediliyor.


22
Bu $list_contains_ip = false;açıklama yanlış görünüyor
Bergi

1
Çakıl dolu bir çanta kolaydır, onları tutmak için uygun bir çantam var. : p
whatsisname,

13
@ Bergi: Haklısın. Bu, işleri karıştırmanın ne kadar kolay olduğunu gösteriyor.
Wallenborn

6
@ whathatname Bu çanta onları tutmak için bir işlev / sınıf / paket denir. gotos kullanmak onları sarsmak ve çantayı atmak gibidir.
Falco

5
Dijkstra'dan gelen alıntıyı seviyorum, bu şekilde koyduğunu duymamıştım ama bu gerçekten iyi bir nokta. Aşağıdan yukarı doğru bir akışa geçmek yerine, birdenbire sayfanın her yerine rastgele sıçrayabilecek bir şeye sahipsiniz. Kısaca şunu söylemek gerekirse oldukça etkileyici.
Bill K

41

Bazı meşru kullanım durumları var GOTO. Örneğin, C'de hata işleme ve temizleme ya da bazı durum makinelerinin uygulanması için. Ancak bu, bu vakalardan biri değil. İkinci örnek daha okunaklı IMHO'dur, ancak daha okunaklı olan, döngüyü ayrı bir işleve çıkarmak ve daha sonra bir eşleşme bulduğunuzda geri dönmek olacaktır. Daha da iyisi olurdu (sözde kodda, tam sözdizimini bilmiyorum):

if (!in_array($ip, $ips)) throw new Exception('Not allowed');

Peki, bu kadar kötü olan ne GOTO? Yapısal programlama, kodu düzenlemek için fonksiyonlar ve kontrol yapıları kullanır, böylece sözdizimsel yapı mantıksal yapıyı yansıtır. Bir şey yalnızca koşullu olarak yürütülürse, koşullu ifade bloğunda görünecektir. Bir döngüde bir şey yapılırsa, döngü bloğunda görünecektir. GOTOkeyfi bir şekilde atlayarak sözdizimsel yapıyı atlatabilmenizi sağlar, böylece kodun takip edilmesini zorlaştırır.

Elbette, başka bir seçeneğiniz yoksa GOTO, ancak işlevler ve kontrol yapılarıyla aynı etkiye ulaşılması durumunda, tercih edilir.


5
@jameslarge it's easier to write good optimizing compilers for "structured" languages.Detaylandırmak ister misiniz? Bir karşı örnek olarak, Rust milleri MIR , derleyicide özellikle döngüleri değiştiren, devam eden, kesilen ve gotos gibi bir ara temsil olan MIR'ı tanıttı; çünkü kontrol edilmesi ve optimize edilmesi daha kolay.
8,

6
"Başka seçeneğiniz yoksa GOTO'yu kullanırsınız" Bu oldukça nadir olurdu . Dürüst olmak gerekirse, başka bir seçeneğinizin olmadığı, mevcut kodun veya benzeri saçmalıkların yeniden düzenlenmesini önleyen tamamen saçma kısıtlamalar dışında bir durum düşünemiyorum .
jpmc26

8
Ayrıca, gotofareler ve koşullandırmalardan oluşan bir sıçan yuvasıyla taklit eden IMO, (OP'nin ikinci örneğinde olduğu gibi), a kullanarak jutlardan çok daha az okunabilir goto.

3
@ 8bittree: Yapısal programlama, derleyicinin hedef dili değil kaynak dil için tasarlanmıştır. Yerli derleyici için hedef dil kesinlikle bir işlemci talimatları vardır değil programlama dili anlamında "yapılandırılmış".
Robert Harvey,

4
@ 8bittree MIR hakkındaki sorunuza cevap verdiğiniz bağlantıda: "Ama MIR'da böyle bir yapıya sahip olmak iyidir, çünkü bunun sadece bir döngü veya bir mola ifade etmek gibi belirli şekillerde kullanılacağını biliyoruz. ." Başka bir deyişle, Rust'a gotoya izin verilmediğinden, yapılandırılmış olduğunu ve gotoslu orta versiyonun da olduğunu biliyorlar. Sonuçta, kodun makine komutlarına gitmesi gerekiyor. Bağlantınızdan elde ettiğim şey, basitçe yüksek seviyeden düşük seviyeli dile dönüşümde artan bir adım atmalarıdır.
JimmyJames

17

Diğerlerinin de söylediği gibi, problemin gotokendisi değil ; Sorun insanların nasıl kullandığı gotove kodun anlaşılmasını ve sürdürülmesini nasıl zorlaştıracağı ile ilgilidir.

Aşağıdaki kod parçasını varsayalım:

       i = 4;
label: printf( "%d\n", i );

Hangi değer için yazdırılır i? Ne zaman basılıyor? İşlevindeki her örneği hesaba katana kadar goto labelbilemezsin. Bu etiketin basit varlığı, basit inceleme ile kod hata ayıklama yeteneğinizi yok eder . Bir veya iki dallı küçük fonksiyonlar için problem değil. Küçük olmayan işlevler için ...

90'lı yılların başlarında, bize 3 boyutlu bir grafik ekran kullanan ve daha hızlı çalışmasını sağlayan bir C kodu verildi. Bu kod sadece 5000 hakkında hatları, ama hepsi o oldu mainve yazar 15 hakkında kullanılan ya da öylesine gotoher iki yönde dallanma s. Başlamak için bu kötü bir koddu, ama bunların varlığı gotoonu daha da kötüleştirdi. İş arkadaşımın kontrol akışını bulması yaklaşık 2 hafta sürdü. Daha da iyisi, gotobunlar kodla sonuçlandı ki kendisiyle o kadar sıkı bir şekilde birleşti ki , hiçbir şeyi bozmadan herhangi bir değişiklik yapamadık .

Seviye 1 optimizasyonu ile derlemeye çalıştık ve derleyici mevcut tüm RAM'leri, ardından mevcut olan tüm takasları yedi ve sonra sistemi panikledi (muhtemelen s'lerin gotokendileriyle hiçbir ilgisi yoktu , ama o anekdotu oraya atmayı seviyorum).

Sonunda, müşteriye iki seçenek sunduk - her şeyi sıfırdan yeniden yazalım ya da daha hızlı donanım alalım.

Daha hızlı donanım aldılar.

Bode'nin kullanım kuralları goto:

  1. Sadece ileriye doğru şube;
  2. Kontrol yapılarını atlamayın (yani bir ifveya forveya whileifadesinin gövdesine dalmayın);
  3. gotoKontrol yapısı yerine kullanmayın

Orada bir durumlardır goto olan doğru cevabı, ancak nadirdir (bir derin iç içe döngünün dışında kırarak sadece ben kullanıyorum ediyorum koyun hakkındadır).

DÜZENLE

Bu son ifadeye göre, işte geçerli olan birkaç geçerli kullanım durumundan biri goto. Aşağıdaki işleve sahip olduğumuzu varsayalım:

T ***myalloc( size_t N, size_t M, size_t P )
{
  size_t i, j, k;

  T ***arr = malloc( sizeof *arr * N );
  for ( i = 0; i < N; i ++ )
  {
    arr[i] = malloc( sizeof *arr[i] * M );
    for ( j = 0; j < M; j++ )
    {
      arr[i][j] = malloc( sizeof *arr[i][j] * P );
      for ( k = 0; k < P; k++ )
        arr[i][j][k] = initial_value();
    }
  }
  return arr;
}

Şimdi, bir sorunumuz var - peki ya mallocaramalardan biri yarıda başarısız olursa? Olası bir olay olması muhtemel olarak, kısmen tahsis edilmiş bir dizi döndürmek istemiyoruz, fonksiyondan bir hatayla kurtulmak da istemiyoruz; Kendimizden sonra temizlik yapmak ve herhangi bir kısmen tahsis edilmiş hafızayı boşaltmak istiyoruz. Kötü bir tahsisat için istisna yapan bir dilde, bu oldukça basittir - zaten tahsis edilmiş olanı serbest bırakmak için bir istisna işleyicisi yazmanız yeterlidir.

C'de, yapılandırılmış istisna işlemeniz yoktur; Her mallocaramanın geri dönüş değerini kontrol etmeniz ve uygun işlemi yapmanız gerekir .

T ***myalloc( size_t N, size_t M, size_t P )
{
  size_t i, j, k;

  T ***arr = malloc( sizeof *arr * N );
  if ( arr )
  {
    for ( i = 0; i < N; i ++ )
    {
      if ( !(arr[i] = malloc( sizeof *arr[i] * M )) )
        goto cleanup_1;

      for ( j = 0; j < M; j++ )
      {
        if ( !(arr[i][j] = malloc( sizeof *arr[i][j] * P )) )
          goto cleanup_2;

        for ( k = 0; k < P; k++ )
          arr[i][j][k] = initial_value();
      }
    }
  }
  goto done;

  cleanup_2:
    // We failed while allocating arr[i][j]; clean up the previously allocated arr[i][j]
    while ( j-- )
      free( arr[i][j] );
    free( arr[i] );
    // fall through

  cleanup_1:
    // We failed while allocating arr[i]; free up all previously allocated arr[i][j]
    while ( i-- )
    {
      for ( j = 0; j < M; j++ )
        free( arr[i][j] );
      free( arr[i] );
    }

    free( arr );
    arr = NULL;

  done:
    return arr;
}

Bunu kullanmadan yapabilir miyiz goto? Tabii ki yapabiliriz - bu sadece biraz ekstra defter tutma gerektirir (ve pratikte benim alacağım yol budur). Ancak, kullanmanın hemen kötü bir uygulama veya tasarım belirtisi gotoolmadığı yerler arıyorsanız , bu az sayıdakilerden biridir.


Bu kuralları severim. Hala kullanmak ister goto-ı kurallarına de kullanmak olmaz hatta bu uyarınca tüm bu mevcut dallanma tek formu olmadıkça dili-ama hata ayıklamak için bir kabus çok fazla olmayacağını görebilirsiniz gotoBu kurallara göre yazılmışlarsa.
Joker

Eğer derinden iç içe geçmiş bir döngüden
ayrılmanız

6
Birinin bir zamanlar benim için özetlediği gibi: “Bu bir sorun değil, bir sorun.”. Bir yazılım optimizasyon uzmanı olarak yapılandırılmamış kontrol akışının bir döngü için derleyiciler (ve insanlar!) Atabileceğini kabul ediyorum. Bir keresinde BLAS işlevinde basit bir durum makinesini (beş durumdan dördü) deşifre etmek için saatler harcadım GOTO, Fortran'ın (in) ünlü ataması ve aritmetik gotos da dahil olmak üzere çeşitli biçimleri kullandım .
njuffa

@njuffa "Bir yazılım optimizasyon uzmanı olarak yapılandırılmamış kontrol akışının bir döngü için derleyiciler (ve insanlar!) atabileceğini kabul ediyorum." - daha fazla detay? Neredeyse her optimizasyon derleyicisinin günümüzde SSA'yı IR olarak kullandığını ve bunun altında da aşağıdakine benzer bir kod kullandığını düşündüm.
Maciej Piechotka

@ MaciejPiechotka Ben derleyici mühendis değilim. Evet, modern derleyicilerin hepsi SSA'yı ara temsillerinde kullanıyor gibi görünüyor. Derleyiciler, tek giriş-tek çıkış kontrol yapılarını tercih eder, SSA kullanımının nasıl oynadığından emin değil misiniz? Üretilen makine kodunun ve derleyici kaynak kullanımının gözlemlenmesi ve derleyici mühendisleriyle yapılandırılmamış kontrol akışı ile yapılan görüşmeler, muhtemelen "gelip gelme" sorunundan dolayı kod dönüşümlerini optimize etmeyi engellemektedir. Derleyici bir optimizasyonu çok pahalıya atlamaya karar verirse, kaynak kullanımı (zaman, bellek) kod performansı üzerinde olumsuz etki yaratabilir.
njuffa

12

return, ve break, continueve throw/ catchhepsi esas olarak gotos'tur - hepsi kontrolü başka bir kod parçasına aktarır ve hepsi de goto'larla uygulanabilir - aslında bir okul projesinde bir kez yaptım, bir PASCAL öğretmeni Pascal'ın ne kadar iyi olduğunu söylüyordu yapısından dolayı temel ... bu yüzden aykırı olmak zorunda kaldım ...

Yazılım Mühendisliği ile ilgili en önemli şey (bu terimi Kodlama üzerinden, devam eden geliştirme ve bakım gerektiren diğer mühendislerle birlikte bir kod temeli oluşturmak için birileri tarafından bir kod tabanı oluşturmak için ödeme yaptığınız bir durumu belirtmek için kullanacağım) kodu Okunabiliyor -Bir şey yapması neredeyse ikincildir. Kodunuz yalnızca bir kez yazılacak, ancak çoğu durumda insanlar günler ve haftaları tekrar ziyaret etmek / yeniden öğrenmek, iyileştirmek ve düzeltmek için harcayacaklar - ve her zaman (veya siz) sıfırdan başlayıp hatırlamaya / anlamaya çalışacaklar senin kodun.

Yıllar boyunca dillere eklenen özelliklerin çoğu, yazılımı daha bakımlı hale getirmek, yazmayı kolaylaştırmamaktır (bazı diller bu yönde olsa da - genellikle uzun vadeli sorunlara neden olurlar ...).

Benzer akış kontrolü ifadeleriyle karşılaştırıldığında, GOTO'lar en iyi şekilde takip etmek kadar kolay olabilir (önerdiğiniz bir durumda kullanılan tek bir goto) ve kötüye kullanıldığında bir kabus - ve çok kolay bir şekilde kötüye ...

Spagetti kabuslarıyla birkaç yıl uğraştıktan sonra biz sadece "Hayır" demiştik, bir topluluk olarak bunu kabul etmeyeceğiz - çok az kişi küçük bir boşluk bırakıldığında bozar - bu gerçekten onlarla ilgili tek sorun. Onları kullanabilirsin ... ama mükemmel bir durum olsa bile, sıradaki adam senin korkunç bir programcı olduğunu varsayar çünkü toplumun tarihini anlamıyorsun.

Kodunuzu daha anlaşılır hale getirmek için birçok başka yapı geliştirilmiştir: İşlevler, Nesneler, Kapsamlar, Kapsülleme, Yorumlar (!) ... yanı sıra "DRY" (kopyalamayı önleme) ve "YAGNI" gibi daha önemli kalıplar / işlemler (Kodun aşırı genelleştirilmesi / karmaşıklığının azaltılması) - hepsi gerçekten SONRAKİ adamın kodunuzu okuması için ithal eder (Muhtemelen siz olacaksınız - ilk başta yaptığınız şeyleri unuttuktan sonra!)


3
Bunu sadece cümle için uyarıyorum, "En önemli şey ... kodu Okunabilir yapmak; bir şeyi yapmak neredeyse ikincildir." Ben sadece biraz farklı şekilde söyleyebilirim; o kadar çok kod katılmıyormuş okunabilir olarak kod yapma basit . Ama ne olursa olsun, yapım o oh-so-doğrudur yapmak şey ikincildir.
Joker

" , Ve / eski saygı kuruluş ilkeleri arasında Disagree tüm esasen gotos olan" yapısal programlama (eğer istisnalar olduğunu savunabiliriz rağmen), go-to kesinlikle bu değildir. Bu sorunun ışığında, bu sözlerden pek kazanılmamıştır. returnbreakcontinuethrowcatch
Eric

@ eric ifadelerin herhangi birini GOTO'larla modelleyebilirsiniz. GOTO'ların hepsinin yapısal programlama ilkeleriyle aynı fikirde olmasını sağlayabilirsiniz - sadece farklı bir sözdizimine sahipler ve işlevselliği tam olarak kopyalamak için "if" gibi diğer işlemleri de içermeleri gerekir. Yapılandırılmış sürümlerin avantajı, yalnızca belirli hedefleri desteklemeyle sınırlandırılmış olmalarıdır - yaklaşık olarak hedefin nerede konumlandırılacağına devam ettiğini görünce BİLİYORSUNUZ. Bahsetmemin nedeni, sorunun kötüye kullanılabildiğine işaret etmekti, doğru kullanılamayacağını.
Bill K,

7

GOTObir araçtır. İyilik için veya kötülük için kullanılabilir.

Kötü eski günlerde, FORTRAN ve BASIC ile birlikte neredeyse tek araç buydu.

O günlerden koda bakarken, bir tane GOTOgördüğünüzde neden orada olduğunu anlamak zorundasınız. Çabucak anlayabileceğiniz standart bir deyimin parçası olabilir ... ya da hiç olmaması gereken bazı kabus kontrol yapısının bir parçası olabilir. Siz bakana kadar hiçbir şey bilmiyorsunuz ve yanılıyor olmak kolaydır.

İnsanlar daha iyisini istediler ve daha gelişmiş kontrol yapıları icat edildi. Bunlar kullanım davalarının çoğunu kapsıyordu ve kötülerin yaktığı insanlar GOTOonları tamamen yasaklamak istedi.

İronik olarak, GOTOnadir olduğunda çok kötü değil. Bir tane gördüğünüzde, devam eden özel bir şey olduğunu bilirsiniz ve ilgili etiketi bulmak kolaydır çünkü yakındaki tek etiket budur.

Bugün için hızlı ileri. Sen öğretim görevlisi öğretim programcısın. Sen olabilir "Çoğu durumda, gelişmiş yeni alaşımlar kullanmalıdır, ancak bazı durumlarda basit söylemek GOTOdaha okunabilir olabilir." Öğrenciler bunu anlamayacaklar. GOTOOkunamayan kod yapmak için kötüye kullanacaklar.

Bunun yerine " GOTOkötü. GOTOKötü. GOTOBaşarısız sınavı " diyorsun . Öğrenciler anlayacaksınız o !


4
Bu aslında tüm kullanımdan kaldırılan şeyler için geçerlidir. Globaller. Tek harfli değişken isimleri. Kendi kendini değiştiren kod. Eval. Hatta filtre uygulanmamış kullanıcı girişi olduğundan şüpheleniyorum. Veba gibi şeylerden kaçınmak için kendimizi şartlandırdığımızda, belli bir kullanımın, belirtildiği gibi, belirli bir sorunun doğru çözümü olup olmadığını değerlendirmek için uygun bir pozisyondayız. Ondan önce, onlara yasaklı olarak davranmamız en iyisidir.
Dewi Morgan

4

Bunun dışında, PHP'dekigoto tüm akış yapıları (ve çoğu dilde) hiyerarşik olarak ele alınmıştır.

Keskin gözlerle incelenen bazı kodları hayal edin:

a;
foo {
    b;
}
c;

Ne olursa olsun, kontrol yapısı ne fooolduğunu ( if, whilevs.), orada belirli izin siparişler sadece a, bve c.

Sen olabilir a- b- cya a- chatta a- b- b- b- c. Ama olabilir asla sahip b- cya a- b- a- c.

... sahip olmadıkça goto.

$a = 1;
first:
echo 'a';
if ($a === 1) {
    echo 'b';
    $a = 2;
    goto first;
}
echo 'c'; 

goto(özellikle de geriye doğru goto), onu yalnız bırakmak ve hiyerarşik, bloklanmış akış yapıları kullanmak en iyisi olacak kadar zahmetli olabilir.

gotobir yer var ama çoğunlukla düşük seviyeli dillerde mikro-optimizasyonlar. IMO, PHP'de bunun için iyi bir yer yok.


Bilginize, örnek kod önerilerinizden her ikisinden de daha iyi yazılabilir.

if(!in_array($ip, $ips, true)) {
    throw new Exception('Not allowed');
}

2

Düşük seviyeli dillerde GOTO kaçınılmazdır. Fakat yüksek seviyede kaçınılması gerekir (dilin desteklemesi durumunda) çünkü programları okumayı zorlaştırıyor .

Her şey kodun okunmasını zorlaştıracak kadar azdır. Yüksek seviyeli diller kodun okunmasını kolaylaştırır, böylece kod derlemesini daha kolay hale getirir, örneğin, assembler veya C.

GOTO küresel ısınmaya neden olmaz ve üçüncü dünyada yoksulluğa neden olmaz. Sadece kodu okumayı zorlaştırır.

Modern dillerin çoğu GOTO'yu gereksiz kılan kontrol yapılarına sahiptir. Java gibi bazılarında bile yok.

Aslında, spaguetti kodu terimi , yapılandırılmış dallanma yapılarının kod nedenlerini takip etmesi zor, kıvrımlıdır.


6
gotokod okumak için istekli yapabilir. Ekstra değişkenler yarattığınızda ve dalları tek bir zıplamaya karşı iç içe geçirdiğinizde kodun okunması ve anlaşılması çok daha zordur.
Matthew Whited

@MatthewWhited Belki de on satırlık bir yöntemle tek bir adımınız varsa. Ancak çoğu yöntem on satırlık değildir ve çoğu zaman GOTO'yu kullanırken çoğu zaman "sadece bu sefer" kullanmazlar.
Tulains Córdova

2
@MatthewWhited Aslında, spaguetti kodu terimi , yapılandırılmamış dallanma yapılarının neden olduğu kodun takip edilmesi zor, karmaşık bir şekilde gelir. Yoksa spaguetti kodunu şimdi kırmızı yapmak daha mı kolay? Olabilir. Vinil dönüyor, neden GOTO olmasın.
Tulains Córdova

3
@Tulains İnsanlar o zaman şikayet etmeye devam ettikleri için bu kadar kötü şeylerin var olduğuna inanmalıyım, fakat gördüğüm zamanların çoğu gotokıvrımlı spagetti kodu örnekleri değil, çoğu zaman anlaşılır dillerdeki kontrol akışı kalıplarını taklit eden oldukça basit şeyler. de bunun için sözdizimine sahiptir: iki en yaygın örnekleri çoklu döngüler ve OP örneğin patlak olan gotouygulamak için kullanılır for- else.

1
Yapılandırılmamış spagetti kodu, fonksiyonların / yöntemlerin bulunmadığı dillerden gelir. gotoistisna yeniden deneme, geri alma, durum makineleri gibi şeyler için de harikadır.
Matthew Whited

1

gotoİfadelerin kendisinde yanlış bir şey yok . Yanlışlar, ifadeyi uygunsuz kullanan bazı kişilerle birliktedir.

JacquesB’nin söylediğine ek olarak (C’de hata işleme), kullanarak gotoiç içe geçmiş bir döngüden çıkmak için kullanıyorsunuz break. Bu durumda daha iyi kullanmak break.

Ancak, iç içe geçmiş bir döngü senaryosu gotoolsaydı , o zaman kullanmak daha şık / basit olurdu. Örneğin:

$allowed = false;

foreach ($ips as $i) {
    foreach ($ips2 as $i2) {
        if ($ip === $i && $ip === $i2) {
            $allowed = true;
            goto out;
        }
    }
}

out:

if (!$allowed) {
    throw new Exception('Not allowed');
}

Yukarıdaki örnek, kendi probleminizde bir anlam ifade etmiyor, çünkü iç içe bir döngüye ihtiyacınız yok. Ama umarım bunun iç içe geçmiş kısmını görürsünüz.

Eklem noktası: IP listeniz küçükse, yönteminiz iyi. Ancak liste büyürse, yaklaşımınızın O (n) ' nin asimptotik en kötü çalışma zamanı karmaşıklığına sahip olduğunu bilin . Listeniz büyüdükçe, O (log n) (bir ağaç yapısı gibi) veya O (1) (çarpışma olmayan bir karma tablo ) elde eden farklı bir yöntem kullanmak isteyebilirsiniz .


6
Ben PHP hakkında emin değilim, ama birçok dil kullanarak destek olacak breakve continuebunlardan herhangi biri genellikle olmalı, bir sayı ile (/ mola için bu etikete sahip döngü devam) ya da bir etiket (mola için / döngüler çoğunun katmanları devam) gotoiç içe döngüler için kullanılması tercih edilir .
8,

@ 8bittree iyi bir nokta. PHP'nin mola bu fantezi olduğunu bilmiyordum . Sadece C’nin tatilinin o kadar da hoş olmadığını biliyorum . Perl'in molası ( en son diyorlar ) aynı zamanda C'lere benziyordu (yani PHP'ler gibi değil) ama bir noktadan sonra fantezi oldu. Sanırım cevabım gittikçe daha az kullanışlı hale geliyor, çünkü daha fazla dil kırılmanın fantezi versiyonlarını sunuyor :)
caveman

3
derinlik değerine sahip bir kırılma, fazladan değişken olmadan sorunu çözmez. Kendisinde ekstra bir karmaşıklık seviyesi yaratan bir değişken.
Matthew Whited

Elbette, sadece iç içe döngüleriniz olması, bir gotoya ihtiyacınız olduğu anlamına gelmez, bu durumu zarif bir şekilde ele almanın başka yolları da vardır.
NPSF3000

@ NPSF3000 Lütfen bir goto ifadesi kullanmadan çıkabileceğiniz , derinliği belirten bir mola sürümüne sahip olmayan bir dili kullanırken çıkabileceğiniz iç içe bir döngü örneği sunabilir misiniz ?
Mağara adamı,

0

Goto ile daha hızlı kod yazabilirim!

Doğru. Umurunda değil

Goto montajda var! Sadece buna jmp diyorlar.

Doğru. Umurunda değil

Goto sorunları daha basit bir şekilde çözer.

Doğru. Umurunda değil

Goto kullanan disiplinli bir geliştirici kodunun elinde okunması daha kolay olabilir.

Doğru. Ancak, ben o disiplinli kodlayıcı oldum. Zamanla kodlamaya ne olduğunu gördüm. Gotoiyi başlar. Sonra kodu tekrar kullanma dürtüsü devreye giriyor. Oldukça yakında kendimi program durumuna baktıktan sonra neler olup bittiğine dair hiçbir ipucunun olmadığı bir kırılma noktasında buluyorum. Gotokod hakkında gerekçeyi zorlaştırır. Biz çalıştık gerçekten zor oluşturma ettik while, do while, for, for each switch, subroutines, functionsbu şeyler yapıyor çünkü daha bütün ve ifve gotobeyin üzerinde zordur.

Yani hayır Bakmak istemiyoruz goto. İkilide canlı ve iyi olduğundan emin olun, ancak bunu kaynağında görmemize gerek yok. Aslında, ifbiraz titrek görünmeye başlıyor.


1
"Goto sorunları daha basit bir şekilde çözüyor." / "Doğru. Umurumda değil." - Kodunuzu, genişletilebilir olanın lehine basit çözümlerden kaçındığınız yerlerde görmekten nefret ediyorum. (Heard of YAGNI?)
user253751

1
@Wildcard ve goto problemleri çözmek için çok basit yollar, başka yollarla çözüldü. Asılı meyveler düşüktür. Belirli bir dille ilgili değil. GotoBaşka bir kod biti sorunu yaparak sorunu çözmenizi sağlar. Ifo soyutlamayı seçmeni sağlar. Soyutlamak için daha iyi yollar ve soyutlamayı seçmek için daha iyi yollar var. Biri için polimorfizm .
candied_orange

2
Sizinle hemfikir olmama rağmen, bu çok kötü ifade edilmiş bir cevap. "Doğru, umursama" hiçbir şey için inandırıcı bir argüman değildir. Bence ana mesajınız şudur: goto, verimli ve güçlü araçlar kullanmayı tercih eden kişilere hitap etse de, daha sonra, özen gösterilse bile, şaşırtıcı derecede büyük miktarda boşa harcanan zamana yol açar.
Artelius

1
@ artelius "Doğru, umursamıyor" teması ikna edici değil. Gitmek için katılacağım ve hala buna karşı geleceğim pek çok noktayı göstermek için. Bu yüzden bu noktaları benimle tartışmak anlamsız. Çünkü bu benim amacım değil. Anladın mı?
candied_orange

1
Sadece iyi bir cevabın sadece fikrinizi ifade etmediğine, aynı zamanda onu açıkladığına ve okuyucunun kendi kararlarını vermesine izin verdiğine inanıyorum. Görüldüğü gibi, neden goto'nun iyi noktalarının sorunlarından daha ağır basmaya yetmediği belirsiz . Çoğumuz saç çekme hataları bulmaya çalışmak saatlerce yok git içerir. Sebep etmesi zor olan tek yapı bu değil. Bu soruyu soran birisi muhtemelen çok daha az deneyimlidir ve perspektife konan şeylere ihtiyaç duyar.
Artelius

-1

Meclis dilleri tipik olarak yalnızca koşullu / koşulsuz atlamalara (GOTO’nun eşdeğeridir. FORTRAN ve BASIC’in daha eski uygulamalarında, sayılan yinelemenin ötesinde hiçbir kontrol bloğu ifadesi yoktur (DO döngüsü), diğer tüm kontrol akışlarını IF ve GOTO’lara bırakır. bu diller sayısal olarak etiketlenmiş bir cümle ile sonlandırılmıştır Sonuç olarak, bu diller için yazılmış kodların takip edilmesi ve hatalara açık olması zor olabilir.

Noktayı vurgulamak için, özenle icat edilmiş " COME FROM " ifadesi var.

GOTO'yu C, C ++, C #, PASCAL, Java, vb. Gibi dillerde kullanmaya gerek yoktur; neredeyse kesinlikle aynı derecede verimli ve çok daha fazla bakım gerektirecek alternatif yapılar kullanılabilir. Kaynak dosyadaki bir GOTO’nun sorun olmayacağı doğrudur. Buradaki sorun, bir kod biriminin takip edilmesini zorlaştırması ve hataya açık hale getirmesi gereğidir. Bu nedenle, kabul edilen bilgelik mümkün olduğunda GOTO'dan kaçınmaktır.

Goto ifadesine ilişkin bu wikipedia makalesi yardımcı olabilir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.