Etiketler ve goto
Etiketler kod satırlarına isimler vermeye ve program akışını bu isimli satırlara yöneltmeye yararlar.
Etiketin isminden ve :
karakterinden oluşurlar:
bitiş: // ← bir etiket
Yukarıdaki etiket, tanımlandığı satıra bitiş ismini verir.
Not: Aslında etiketler herhangi iki deyimin arasında da bulunabilirler ve bulundukları o noktayı isimlendirmiş olurlar. Ancak bu kullanım yaygın değildir:
birİfade(); bitiş: başkaİfade();
goto
İngilizce'de "git" anlamına gelen goto
, program akışını ismi belirtilen satıra yönlendirir:
void birİşlev(bool koşul) { writeln("birinci"); if (koşul) { goto bitiş; } writeln("ikinci"); bitiş: writeln("üçüncü"); }
Yukarıdaki işlev, koşul
'un true
olduğu durumlarda doğrudan bitiş
isimli satıra gider, ve "ikinci" yazdırılmaz:
birinci üçüncü
Etiketler ve goto
D'ye C'den geçmiştir. goto
, yapısal programlamaya aykırı olduğu için C'de bile kaçınılması önerilen bir olanaktır. Doğrudan belirli satırlara yönlendiren goto
'lar yerine while
, for
, ve diğer yapısal deyimlerin kullanılması önerilir.
Örneğin yukarıdaki kodun eşdeğeri, şimdiye kadar çoğu kodda gördüğümüz gibi, goto
kullanmadan şöyle yazılabilir:
void birİşlev(bool koşul) { writeln("birinci"); if (!koşul) { writeln("ikinci"); } writeln("üçüncü"); }
Buna rağmen goto
'nun C dilinde iki tane geçerli kullanımı vardır. Bu kullanımların ikisi de D'de gereksizdir.
D'de gerekmeyen, sonlandırıcı bölge
goto
'nun C'deki geçerli bir kullanımı, işlevlerin sonlarına yazılan ve o işlevde ayrılmış olan kaynakların geri verilmesi gibi işlemleri içeren sonlandırıcı bölgedir:
// --- C kodu ---
int birIslev() {
// ...
if (hata) {
goto bitis;
}
// ...
bitis:
// ... sonlandirma islemleri buraya yazilir ...
return hata;
}
D'de kaynak yönetimi için başka olanaklar bulunduğu için bu kullanım D'de gereksizdir. D'de sonlandırma işlemleri; çöp toplayıcı, sonlandırıcı işlevler, hata atma düzeneğinin catch
ve finally
blokları, scope()
deyimleri, vs. gibi olanaklarla sağlanır.
Not: Bu kullanıma C++'ta da gerek yoktur.
D'de gerekmeyen, iç içe döngülerde kullanımı
goto
'nun C'deki diğer geçerli kullanımı, iç içe döngülerin daha dışta olanlarını etkilemektir.
Döngüyü kırmak için kullanılan break
, ve döngüyü hemen ilerletmek için kullanılan continue
, yalnızca en içteki döngüyü etkiler. C'de ve C++'ta dıştaki döngüyü kırmanın bir yolu, döngüden sonraki bir etikete gitmektir; dıştaki döngüyü ilerletmenin bir yolu da, onun hemen içindeki bir etikete gitmektir:
// --- C kodu --- while (birKosul) { while (baskaKosul) { // yalnizca icteki donguyu etkiler continue; // yalnizca icteki donguyu etkiler break; // distaki icin 'continue' gibi calisir goto distakiniIlerlet; // distaki icin 'break' gibi calisir goto distakindenCik; } distakiniIlerlet: ; } distakindenCik:
Not: Bu kullanıma C++ programlarında da rastlanabilir.
Aynı durum iç içe bulunan switch
deyimlerinde de vardır; break
yalnızca içteki switch
'i etkilediğinden dıştakinden de çıkmak için goto
kullanılabilir.
D'de goto
'nun bu kullanımına da gerek yoktur. Onun yerine biraz aşağıda göstereceğim döngü etiketleri kullanılır.
goto
'nun kurucu işlevleri atlama sorunu
Kurucu işlevler nesnelerin kuruldukları satırlarda çağrılırlar. Bunun nedenlerinden birisi, nesnenin kurulması için gereken bilginin henüz mevcut olmaması olabilir. Bir başka neden, belki de hiç kullanılmayacak olan bir nesneyi kurmak için gereksizce zaman ve kaynak harcamamaktır.
Nesnelerin kuruldukları satırlar goto
ile atlandığında, henüz kurulmadıklarından hatalı sonuçlar doğuran nesnelerle karşılaşılabilir:
if (koşul) { goto birEtiket; // kurucu işlevi atlar } auto nesne = Yapı(42); // nesnenin kurulduğu satır birEtiket: nesne.birİşlem(); // HATA: belki de hazır olmayan nesne
Derleyici bu hatayı önler:
Error: goto skips declaration of variable deneme.main.s
Döngü etiketleri
D'de döngülerden hemen önce etiketler tanımlanabilir. continue
ve break
anahtar sözcüklerinde de etiket belirtilebilir ve o döngülerin etkilenmeleri sağlanabilir:
dışDöngü: while (birKoşul) { while (başkaKoşul) { // içteki döngüyü ilerletir continue; // içteki döngüden çıkar break; // dıştaki döngüyü ilerletir continue dışDöngü; // dıştaki döngüden çıkar break dışDöngü; } }
Aynısı switch
deyimleri için de geçerlidir. break
deyimlerinin dıştaki bir switch
'i etkilemesi için o switch
deyiminden önce de etiket tanımlanabilir.
case
bölümlerinde kullanımı
goto
'nun case
bölümlerinde nasıl kullanıldıklarını switch
ve case
bölümünde görmüştük:
-
goto case
, bir sonrakicase
'e atlanmasını sağlar. -
goto default
,default
bölümüne atlanmasını sağlar. goto case ifade
, ifadeye uyancase
'e atlanmasını sağlar.
Özet
goto
'nun riskli kullanımlarına D'de gerek yoktur.- İç içe döngülerden veya
switch
deyimlerinden hangisinin etkileneceğini belirtmek içinbreak
vecontinue
deyimlerinde etiket kullanılabilir. case
bölümlerindekigoto
'lar diğercase
vedefault
bölümlerine atlanmasını sağlarlar.