switch ve case
switch, çoklu koşul gibi çalışan bir deyimdir ve bu açıdan bir "if else if" zincirine benzer. Buradaki kullanımında "durum" anlamına gelen case, switch'in denetlediği değerin karşılaştırıldığı durumları belirlemek için kullanılır; kendisi bir deyim değildir.
switch, parantez içinde bir ifade alır; o ifadenin değerini kendi kapsamı içindeki case'lerle karşılaştırır ve değere eşit olan ilk case'in işlemlerini işletir. Söz dizimini şöyle gösterebiliriz:
switch (ifade) { case değer_1: // ifade'nin değer_1'e eşit olduğu durumdaki işlemler // ... break; case değer_2: // ifade'nin değer_2'ye eşit olduğu durumdaki işlemler // ... break; // ... başka case'ler ... default: // hiçbir değere uymayan durumdaki işlemler // ... break; }
Her ne kadar bir koşul gibi çalışsa da, switch'in aldığı ifade, bir mantıksal ifade olarak çalışmaz. Yani bir if'te olduğu gibi "eğer böyleyse" anlamında, veya bir while'da olduğu gibi "böyle olduğu sürece" anlamında değildir. switch'teki ifadenin değerinin, case'lerdeki değerlere eşit olup olmadığına bakılır. Yani buradaki koşul, bir eşitlik karşılaştırmasıdır.
İfadenin değerine eşit olan bir case değeri varsa, o case'in altındaki işlemler işletilir. Eğer yoksa, "varsayılan" anlamına gelen default'un altındaki işlemler işletilir. Bu işlemler break deyimine kadar devam eder; break, switch'in işinin bitmesini sağlar.
Bu açıdan bakınca, bir "if else if" zinciri gibi düşünülebilir:
auto değer = ifade; if (değer == değer_1) { // değer_1 durumundaki işlemler // ... } else if (değer == değer_2) { // değer_2 durumundaki işlemler // ... } // ... başka 'else if'ler ... } else { // hiçbir değere uymayan durumdaki işlemler // ... }
Bu "if else if", switch'in tam eşdeğeri değildir. Nedenlerini aşağıdaki başlıklarda açıklıyorum.
case'in kapsamı yoktur
if koşulunun kapsamı olduğu için, kapsamdaki işlemler sonlanınca bütün if deyiminin işi bitmiş olur. switch'te ise; ifadenin değerine eşit bir case bulunduğu zaman, programın işleyişi o case'e atlar ve bir break ile karşılaşılana kadar devam eder. Bu, break'i olmayan case'lerden, hemen altlarındaki case'lere devam edilmesine neden olur:
switch (değer) { case 5: writeln("beş"); // burada break yok... case 4: writeln("dört"); break; default: writeln("bilmiyorum"); break; }
değer 5 olduğunda case 5 satırının altına gidilir ve orada "beş" yazdırılır. Ama o satırdan sonraki ilk break'e gelene kadar "dört" de yazdırıldığı için çıktıda ikisi de yer alır:
beş dört
Bir sonraki case'e geçilmesini özellikle istemiyorsanız break'leri unutmayın. Doğrusu, böyle bir program davranışı için normalde bir neden yoktur. Her zaman için break'leri hatırlayın.
İfadenin değeri ancak tamsayı, bool, veya dizgi olabilir
if'te eşitlik karşılaştırmasında herhangi bir tür kullanılabilir. switch'te ise ifade değeri olarak ancak tamsayılar, bool, veya dizgiler kullanılabilir.
switch (işlem) { case "toplama": sonuç = birinci + ikinci; break; case "çıkarma": sonuç = birinci - ikinci; break; case "çarpma": sonuç = birinci * ikinci; break; case "bölme": sonuç = birinci / ikinci; break; default: throw new Geçersizİşlem; }
Not: Yukarıdaki kod, hiçbir case'e uymayan durumda bir hata atmaktadır. Hataları ilerideki bir derste göreceğiz.
Her ne kadar ifade türü olarak bool da kullanılabiliyor olsa da, false ve true diye iki değeri olan bu tür için çoğu durumda if'in veya ?: üçlü işlecinin daha uygun olduğunu düşünebilirsiniz.
case değerleri derleme zamanında bilinmelidir
if deyimlerindeki eşitlik koşullarında, eşitliğin her iki tarafındaki değer de programın çalışması sırasında belirlenmiş olabilir. Örneğin bu kodda, birisi kullanıcı tarafından girilmiş ve diğeri rastgele seçilmiş iki değerin eşitliği karşılaştırılıyor:
if (tahminEdilenSayı == tutulanSayı) { writeln("Bildiniz!"); }
Oysa case değerlerinin derleme zamanında bilinmeleri gerekir. switch'in ifadesi çalışma zamanında hesaplanır, ama case değerleri derleme zamanında bilinmelidir.
Aralık değerleri
Belirli bir değer aralığındaki durumlar case'ler arasına .. karakterleri yerleştirilerek belirtilir:
switch (zarDeğeri) { case 1: writeln("Sen kazandın"); break; case 2: .. case 5: writeln("Berabere"); break; case 6: writeln("Ben kazandım"); break; default: // Aslında bu durumun hiç gerçekleşmemesi gerekir! // Çünkü yukarıdaki durumlar zarın bütün değerlerini // kapsamaktadırlar. break; }
Yukarıda zarla oynanan bir oyunda zarın [2,5] aralığındaki değerlerinde berabere kalınmaktadır.
Ayrık değerler virgülle bildirilir
Yukarıdaki oyunda [2,5] aralığında değil de, 2 ve 4 değerleri geldiğinde berabere kalındığını varsayalım. Öyle durumlarda case'in değerlerinin aralarına virgül yazılır:
case 2, 4: writeln("Berabere"); break;
final switch deyimi
Bu deyim de switch gibidir, ama bazı kısıtlamaları vardır:
defaultbölümü bulunamaz; zaten bu durum bazı koşullarda anlamsızdır: örneğin zarın değerlerinin altısının da işlemlerinin belirli olduğu bir durumdadefaultbölüme gerek yokturcase'lerde aralıklı değerler kullanılamaz (virgülle gösterilen ayrık değerler olur)- eğer ifade bir
enumtürüyse, türün bütün değerlerinincase'ler tarafından kapsanmış olmaları gerekir (enum'ları çok yakında öğreneceksiniz)
final switch (zarDeğeri) { case 1: writeln("Sen kazandın"); break; case 2, 4: writeln("Berabere"); break; case 3, 5, 6: writeln("Ben kazandım"); break; }
Ne zaman kullanmalı
Yukarıda anlatılanlardan anlaşıldığı gibi; switch, bir ifadenin derleme zamanında bilinen değerlerle karşılaştırıldığı durumlarda kullanışlıdır.
Eğer karşılaştırılacak değer yalnızca iki taneyse, switch yerine bir "if else" daha uygun olabilir. Örneğin yazı/tura gibi bir sonuçta if deyimi yeterlidir:
if (yazıTuraSonucu == yazı) { // ... } else { // ... }
Genel bir kural olarak, switch'i üç veya daha çok durum için düşünebilirsiniz. Bu konuda da karar sizin! :o)
Problemler
- Yukarıdaki örneklerden birisindeki gibi bir hesap makinesi yapın. Kullanıcıdan "işlem birinci_sayı ikinci_sayı" düzeninde komut alsın ve işleme göre hesap yapsın. Örneğin "topla 5 7" geldiğinde ekrana 12 yazsın.
- Hesap makinesini geliştirin ve "topla" gibi sözlü işlemler yanında "+" gibi simgeleri de desteklemesini sağlayın: "+ 5 7" komutu da aynı şekilde çalışsın.
- Program, bilinmeyen bir işlem girildiğinde hata atsın. Yukarıdaki gibi bir
throwdeyimiyle kullanabilmek içinvoid mainsatırından hemen önce bir hata sınıfı tanımlamanız gerekir. Bu sınıfı basitçe şöyle tanımlayabilirsiniz:
Komutu girişten şu şekilde okuyabilirsiniz:
din.readf("%s %f %f".dup, &işlem, &birinci, &ikinci);
class Geçersizİşlem {} void main() { // ...
D.ershane
Forum
Wiki
Projeler
Tanıtım
İletişim
Hakları