is
İfadesi
Bu ifade, daha önce null
değeri ve is
işleci bölümünde gördüğümüz is
işlecinden anlam ve yazım açısından farklıdır:
a is b // daha önce gördüğümüz is işleci is (/* ... */) // is ifadesi
Bu bölümün konusu olan is
ifadesi derleme zamanında işletilir ve parantez içindeki ifadeye bağlı olan bir değer üretir. Ürettiği değerin türü int
'tir; koşul geçerli olduğunda 1, geçersiz olduğunda 0 değerini alır.
is
'in aldığı koşul bir mantıksal ifade değildir ama is
'in kendi değeri bir mantıksal ifadede kullanılmaya elverişlidir. Örneğin if
deyimiyle, ve derleme zamanında işletildiği için daha da uygun olarak static if
deyimiyle kullanılabilir.
Aldığı koşul türlerle ilgilidir ve bir kaç özel biçimden birisi olarak yazılmak zorundadır. En çok şablon parametrelerini denetlemede ve şablon parametre türleriyle ilgili bilgi toplamada yararlıdır.
is (Tür)
Tür
'ün anlamsal olarak geçerli bir tür olup olmadığını denetler.
is
'in bu kullanımı için bu noktada tek başına örnekler bulmak oldukça zor. Bunun yararını daha sonraki bölümlerde şablon parametreleri ile kullanırken göreceğiz.
static if (is (int)) { writeln("geçerli"); } else { writeln("geçersiz"); }
Yukarıdaki koşulda kullanılan int
, geçerli bir türdür:
geçerli
Başka bir örnek olarak, eşleme tablosu indeks türü olarak void
kullanmak geçersiz olduğu için bu örnekte else
bloğu işletilir:
static if (is (string[void])) { writeln("geçerli"); } else { writeln("geçersiz"); }
geçersiz
is (Tür Takmaİsim)
Yukarıdaki ile aynı şekilde çalışır. Ek olarak, koşul geçerli olduğunda Takmaİsim
'i türün yeni takma ismi olarak tanımlar:
static if (is (int Yeniİsim)) { writeln("geçerli"); Yeniİsim değişken = 42; // int ve Yeniİsim aynı anlamda } else { writeln("geçersiz"); }
Takma ismin bu şekilde is
ifadesinin içinde tanımlanabilmesi, daha sonra göreceğimiz karmaşık is
ifadelerinde yararlıdır.
is (Tür : ÖzelTür)
Tür
'ün belirtilen özel türe otomatik olarak dönüşüp dönüşemediğini denetler.
Tür Dönüşümleri bölümünde gördüğümüz temel tür dönüşümlerini, veya Türeme bölümünde gördüğümüz "bu alt sınıf, o üst sınıfın türündendir" ilişkilerini denetlemede kullanılır.
import std.stdio; interface Saat { void zamanıOku(); } class ÇalarSaat : Saat { override void zamanıOku() { writeln("10:00"); } } void birİşlev(T)(T nesne) { static if (is (T : Saat)) { // Eğer buraya geldiysek, şablon parametresi olan T // Saat yerine kullanılabilen bir türdür writeln("bu bir Saat; zamanı söyleyebiliriz"); nesne.zamanıOku(); } else { writeln("bu bir Saat değil"); } } void main() { auto değişken = new ÇalarSaat; birİşlev(değişken); birİşlev(42); }
O kod, birİşlev
şablonu Saat
'e dönüşebilen bir tür ile çağrıldığında nesne
'nin zamanıOku
işlevini de çağırmaktadır. Tür int
olduğunda ise else
bloğu derlenmektedir:
bu bir Saat; zamanı söyleyebiliriz ← ÇalarSaat için 10:00 ← ÇalarSaat için bu bir Saat değil ← int için
is (Tür Takmaİsim : ÖzelTür)
Yukarıdakiyle aynı şekilde çalışır. Ek olarak, koşul geçerli olduğunda Takmaİsim
'i koşulu sağlayan türün yeni takma ismi olarak tanımlar.
is (Tür == ÖzelTür)
Tür
'ün belirtilen özel türün aynısı olup olmadığını, veya aynı belirtece sahip olup olmadığını denetler.
Aynı tür anlamında
Yukarıdaki örnek kodu değiştirsek ve :
yerine ==
kullansak, bu sefer ÇalarSaat
için de geçersiz olacaktır:
static if (is (T == Saat)) { writeln("bu bir Saat; zamanı söyleyebiliriz"); nesne.zamanıOku(); } else { writeln("bu bir Saat değil"); }
ÇalarSaat
Saat
'ten türediği için bir Saat
'tir, ama Saat
'in aynısı değildir. O yüzden koşul hem ÇalarSaat
için, hem de int
için geçersizdir:
bu bir Saat değil bu bir Saat değil
Aynı belirtece sahip anlamında
ÖzelTür
yerine bir belirteç kullanıldığında türün o belirtece uyup uymadığını denetler. Bu kullanımda belirteç olarak aşağıdaki anahtar sözcükler kullanılabilir (bu sözcüklerden bazılarını daha sonraki bölümlerde göreceğiz):
void birİşlev(T)(T nesne) { static if (is (T == class)) { writeln("bu bir sınıf türü"); } else static if (is (T == enum)) { writeln("bu bir enum"); } else static if (is (T == const)) { writeln("bu 'const' bir tür"); } else { writeln("bu başka bir tür"); } }
İşlev şablonları çağrıldıkları türe göre değişik davranacak şekilde kodlanabilirler. Koşulun değişik bloklarının etkinleştiğini göstermek için şöyle deneyebiliriz:
auto değişken = new ÇalarSaat; birİşlev(değişken); // (enum HaftaGünleri biraz aşağıda tanımlanıyor) birİşlev(HaftaGünleri.Pazartesi); const double sayı = 1.2; birİşlev(sayı); birİşlev(42);
Çıktısı:
bu bir sınıf türü bu bir enum bu 'const' bir tür bu başka bir tür
is (Tür isim == Belirteç)
Yukarıdaki ile aynı şekilde çalışır. Ek olarak, koşul geçerli olduğunda isim
'i duruma göre farklı anlamlarda tanımlar. isim
, yukarıdaki takma isimli kullanımlardaki gibi doğrudan türün takma ismi olabileceği gibi, belirtece bağlı olarak başka bir bilgi de olabilir:
Belirteç |
isim 'in anlamı |
---|---|
struct |
koşulu sağlayan tür |
union |
koşulu sağlayan tür |
class |
koşulu sağlayan tür |
interface |
koşulu sağlayan tür |
super |
üst tür ve arayüzlerden oluşan çokuzlu |
enum |
enum 'un gerçekleştirildiği temel tür |
function |
işlev parametrelerinden oluşan çokuzlu |
delegate |
delegate 'in türü |
return |
işlevin, delegate 'in, veya işlev göstergesinin dönüş türü |
__parameters |
işlevin, delegate 'in, veya işlev göstergesinin parametrelerinden oluşan çokuzlu |
const |
koşulu sağlayan tür |
immutable |
koşulu sağlayan tür |
shared |
koşulu sağlayan tür |
Bu olanağın nasıl çalıştığını göstermek için önce bazı türler tanımlayalım:
struct Nokta { // ... } interface Saat { // ... } class ÇalarSaat : Saat { // ... } enum HaftaGünleri { Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar } char foo(double kesirli, int tamsayı, Saat saat) { return 'a'; }
is
ifadesinin bu değişik türlerle kullanımlarını göstermek için aşağıdaki gibi bir işlev şablonu yazılabilir. İşlevin çağrıldığı türlerin, nesnelerin, ve isim
'in ne anlamlara geldiklerini açıklama satırları olarak yazdım:
void birİşlev(T)(T nesne) { static if (is (T YerelTür == struct)) { writefln("\n--- struct ---"); // T ve YerelTür aynı anlamdadır; 'nesne', bu işleve // gelen yapı nesnesidir writeln("Yeni bir ", YerelTür.stringof, " nesnesini kopyalayarak oluşturuyorum"); YerelTür yeniNesne = nesne; } static if (is (T üstTürler == super)) { writeln("\n--- super ---"); // 'üstTürler' çokuzlusu bütün üst türleri içerir; // 'nesne', bu işleve gelen sınıf nesnesidir writeln(T.stringof, " sınıfının ", üstTürler.length, " adet üst türü var"); writeln("hepsi birden: ", üstTürler.stringof); writeln("en üstteki: ", üstTürler[0].stringof); } static if (is (T AsılTür == enum)) { writeln("\n--- enum ---"); // 'AsılTür', enum değerlerini gerçekleştirmek için // kullanılan asıl türdür; 'nesne', bu işleve gelen // enum değeridir writeln(T.stringof, " enum türü, perde arkasında ", AsılTür.stringof, " olarak gerçekleştirilmiştir"); } static if (is (T DönüşTürü == return)) { writeln("\n--- return ---"); // 'DönüşTürü', işlevin dönüş türüdür; bu işleve // parametre olarak gelen 'nesne', bir işlev // göstergesidir writeln("Bu, dönüş türü ", DönüşTürü.stringof, " olan bir işlev:"); writeln(" ", T.stringof); write("çağırıyoruz... "); // Not: İşlev göstergeleri işlev gibi çağrılabilirler DönüşTürü sonuç = nesne(1.5, 42, new ÇalarSaat); writeln("ve sonuç: ", sonuç); } }
O işlevi yukarıdaki farklı türlerle şöyle çağırabiliriz:
// Yapı nesnesiyle birİşlev(Nokta()); // Sınıf nesnesiyle birİşlev(new ÇalarSaat); // enum değerle birİşlev(HaftaGünleri.Pazartesi); // İşlev göstergesiyle birİşlev(&foo);
Çıktısı:
--- struct --- Yeni bir Nokta nesnesini kopyalayarak oluşturuyorum --- super --- ÇalarSaat sınıfının 2 adet üst türü var hepsi birden: (Object, Saat) en üstteki: Object --- enum --- HaftaGünleri enum türü, perde arkasında int olarak gerçekleştirilmiştir --- return --- Bu, dönüş türü char olan bir işlev: char function(double kesirli, int tamsayı, Saat saat) çağırıyoruz... ve sonuç: a
is (/* ... */ Belirteç, ŞablonParametreListesi)
Şablon parametre listesi içeren is
ifadesinin dört farklı kullanımı vardır:
is (Tür : Belirteç, ŞablonParametreListesi)
is (Tür == Belirteç, ŞablonParametreListesi)
is (Tür isim : Belirteç, ŞablonParametreListesi)
is (Tür isim == Belirteç, ŞablonParametreListesi)
Bu dört kullanım çok daha karmaşık ifadeler yazmaya olanak verir.
isim
, Belirteç
, :
, ve ==
hep yukarıdaki kullanımlarıyla aynı anlamdadırlar.
ŞablonParametreListesi
ise hem koşulun parçası olarak işlem görür hem de bütün koşul sağlandığında otomatik olarak uygun tür isimleri tanımlamaya yarar. Şablonların tür çıkarsama olanağı ile aynı biçimde işler.
Örnek olarak, indeks değeri string
olan eşleme tabloları kullanıldığında özel işlemler yapılması gereksin. Yalnızca böyle türlere uymaya çalışan bir is
ifadesi şöyle yazılabilir:
static if (is (T == Değer[İndeks], // (1) Değer, // (2) İndeks : string)) { // (3)
O koşulu üç bölüm olarak açıklayabiliriz. Bunların son ikisi ŞablonParametreListesi
'ni oluşturmaktadır:
T
,Değer[İndeks]
yazımına uygunsaDeğer
herhangi bir tür iseİndeks
birstring
ise (şablon özellemesi söz dizimi)
Belirteç
olarak Değer[İndeks]
kullanılmış olması şablon parametresi olan T
'nin bir eşleme tablosu türü olmasını gerektirir. Değer
için hiçbir koşul belirtilmemiş olması onun herhangi bir tür olmasının yeterli olduğu anlamına gelir. Ek olarak, eşleme tablosunun indeks türünün de özellikle string
olması gerekmektedir. Dolayısıyla, yukarıdaki is
ifadesi, "T
, indeks türü string
olan bir eşleme tablosu ise" anlamına gelmektedir.
Bu is
ifadesini kullanan ve dört farklı türle çağrılan bir örnek şöyle yazılabilir:
import std.stdio; void birİşlev(T)(T nesne) { writeln("\n--- ", T.stringof, " ile çağrıldık ---"); static if (is (T == Değer[İndeks], Değer, İndeks : string)) { writeln("Evet, koşul sağlandı."); writeln("değer türü : ", Değer.stringof); writeln("indeks türü: ", İndeks.stringof); } else { writeln("Hayır, koşul sağlanmadı."); } } void main() { int sayı; birİşlev(sayı); int[string] intTablosu; birİşlev(intTablosu); double[string] doubleTablosu; birİşlev(doubleTablosu); dchar[long] dcharTablosu; birİşlev(dcharTablosu); }
Koşul, yalnızca indeks türü string
olan eşleme tabloları için sağlanmaktadır:
--- int ile çağrıldık --- Hayır, koşul sağlanmadı. --- int[string] ile çağrıldık --- Evet, koşul sağlandı. değer türü : int indeks türü: string --- double[string] ile çağrıldık --- Evet, koşul sağlandı. değer türü : double indeks türü: string --- dchar[long] ile çağrıldık --- Hayır, koşul sağlanmadı.