Koşullu Derleme
Programın bazı bölümlerinin belirli koşullara bağlı olarak farklı derlenmesi, veya hiç derlenmemesi istenebilir. D'nin koşullu derleme olanakları bu konuda kullanılır.
Derleme ile ilgili oldukları için, bu koşullar yalnızca derleme zamanında değerlendirilir; programın çalışması sırasında etkileri yoktur. Çalışma zamanında etkili olan if, for, while gibi D olanakları koşullu derleme olanakları değildir.
Aslında önceki derslerde koşullu derleme olarak kabul edilebilecek başka olanaklar görmüştük:
- Birim testi bloklarındaki kodlar yalnızca
-unittestderleyici seçeneği kullanıldığında derlenir ve çalıştırılır - Sözleşmeli programlama olanakları olan
in,out, veinvariantblokları-releaseseçeneği kullanılmadığı zaman etkindir
Yukarıdakiler, programın doğruluğunu arttırma amacına yönelik yardımcı olanaklar olarak görülebilir. Derleyici seçeneklerine bağlı olarak kullanılıp kullanılmamaları, programın asıl davranışını zaten değiştirmemelidir.
- Şablon özellemeleri, yalnızca belirtilen türler için etkilidir. O türler programda kullanılmadığında, özelleme kodu derlenmez ve programa dahil edilmez:
void değişTokuş(T)(ref T birinci, ref T ikinci) { T geçici = birinci; birinci = ikinci; ikinci = geçici; } unittest { auto bir = 'ğ'; auto iki = 'ş'; değişTokuş(bir, iki); assert(bir == 'ş'); assert(iki == 'ğ'); } void değişTokuş(T : uint)(ref T birinci, ref T ikinci) { birinci ^= ikinci; ikinci ^= birinci; birinci ^= ikinc; // DİKKAT: sondaki i harfi unutulmuş! } void main() {}
Yukarıdaki işlevin uint özellemesi, daha hızlı olacağı düşünüldüğü için bit işleci ^ (ya da işlemi) kullanılarak yazılmış.
Sonundaki yazım hatasına rağmen, yukarıdaki program derlenir ve çalışır. Bunun nedeni, değişTokuş işlevinin uint türü ile çağrılmamış olması, ve bu yüzden uint özellemesinin derlenmemiş olmasıdır.
O programdaki hata, işlev uint türü ile çağrılana kadar ortaya çıkmaz. Bunu, birim testlerinin önemini gösteren bir başka örnek olarak da görebilirsiniz. Birim testi de yazılmış olsa, o özellemedeki hata, işlev yazıldığı sırada ortaya çıkar:
unittest { uint i = 42; uint j = 7; değişTokuş(i, j); assert(i == 7); assert(j == 42); }
Görüldüğü gibi, şablon özellemelerinin de koşullu olarak derlendiklerini kabul edebiliriz.
D'nin koşullu derlemeyi destekleyen ve bütünüyle bu amaç için tasarlanmış üç olanağı daha vardır:
debugversionstatic if
debug
Program geliştirme aşamasında yararlı olan bir olanak debug belirtecidir. Bu belirteçle işaretlenmiş olan ifadeler ve bloklar yalnızca derleyicinin -debug seçeneği kullanıldığında etkilidir:
debug koşullu_derlenen_bir_ifade; debug { // ... koşullu derlenen ifadeler ... }
Yukarıdaki tek ifade de, blok içindeki ifadeler de ancak -debug derleyici seçeneği etkin olduğunda derlenir.
Şimdiye kadarki programların hemen hemen hepsinde programın nasıl işlediğini gösteren "ekliyorum", "çıkartıyorum", gibi satırlar kullandık. Böylece algoritmaların işleyişlerini görsel bir hale getirerek olası hatalarını bulabiliyorduk. "debug", hata gidermek anlamına gelir ve bu konuda yararlıdır.
Bunun bir örneği olarak Şablonlar dersinde gördüğümüz ikiliAra işlevine bakalım. O algoritmanın açıklama satırlarını çıkartıyorum ve bilerek hatalı olarak yazıyorum:
import std.cstream; // DİKKAT! Bu algoritma hatalıdır int ikiliAra(const int[] değerler, in int değer) { if (değerler.length == 0) { return -1; } const auto ortaNokta = değerler.length / 2; if (değer == değerler[ortaNokta]) { return ortaNokta; } else if (değer < değerler[ortaNokta]) { return ikiliAra(değerler[0 .. ortaNokta], değer); } else { return ikiliAra(değerler[ortaNokta + 1 .. $], değer); } } void main() { int[] sayılar = [ -100, 0, 1, 2, 7, 10, 42, 365, 1000 ]; int indeks = ikiliAra(sayılar, 42); dout.writefln("Konum: ", indeks); }
Yukarıdaki programı çalıştırdığımızda, 42'nin 6 olarak bildirilmesi gereken konumunun yanlış bildirildiğini görürüz:
Konum: 1
Bu hatayı bulmanın bir yolu, işlevin önemli noktalarına işlemler hakkında bilgiler veren satırlar eklemektir:
int ikiliAra(const int[] değerler, in int değer) { dout.writefln(değerler, " içinde ", değer, " arıyorum"); if (değerler.length == 0) { dout.writefln(değer, " bulunamadı"); return -1; } const auto ortaNokta = değerler.length / 2; dout.writefln("bakılan konum: ", ortaNokta); if (değer == değerler[ortaNokta]) { dout.writefln(değer, ", ", ortaNokta, " konumunda bulundu"); return ortaNokta; } else if (değer < değerler[ortaNokta]) { dout.writefln("ilk yarıda olması gerek"); return ikiliAra(değerler[0 .. ortaNokta], değer); } else { dout.writefln("son yarıda olması gerek"); return ikiliAra(değerler[ortaNokta + 1 .. $], değer); } }
Programın şimdiki çıktısı, algoritmanın işleyiş adımlarını gösterir:
[-100,0,1,2,7,10,42,365,1000] içinde 42 arıyorum bakılan konum: 4 son yarıda olması gerek [10,42,365,1000] içinde 42 arıyorum bakılan konum: 2 ilk yarıda olması gerek [10,42] içinde 42 arıyorum bakılan konum: 1 42, 1 konumunda bulundu Konum: 1
Hatanın bu çıktıdan yararlanılarak bulunduğunu ve giderildiğini varsayalım. Hata giderildikten sonra artık writefln satırlarına gerek kalmaz ve hatta silinmeleri gerekir. Buna rağmen, o satırları silmek de bir israf olarak görülebilir; çünkü bugün silinirlerse, belki de ileride tekrar gerekebilirler.
Onun yerine, bu satırların başına debug anahtar sözcüğü yazılabilir:
debug dout.writefln(değer, " bulunamadı");
O satırlar artık yalnızca -debug derleyici seçeneği kullanıldığında etkin olacaktır:
dmd deneme.d -ofdeneme -w -debug
Böylece, programın normal işleyişi sırasında çıktıya hiçbir bilgi yazdırılmayacak; bir hata görüldüğünde ise -debug kullanılarak algoritmanın işleyişi hakkında bilgi alınabilecektir.
debug(isim)
debug belirtecinin çok yerde kullanılması durumunda programın çıktısı çok kalabalıklaşabilir. Böyle durumlarda debug belirteçlerine isimler verebilir ve onların yalnızca komut satırında belirtilenlerinin etkinleşmelerini sağlayabiliriz:
debug(ikili_arama) dout.writefln(değer, " bulunamadı");
İsimli debug belirteçlerini etkinleştirmek için komut satırında -debug=isim yazılır:
dmd deneme.d -ofdeneme -w -debug=ikili_arama
İsimli debug belirteçleri de birden fazla ifade için kullanılabilir:
debug(ikili_arama) { // ... koşullu derlenen ifadeler ... }
Aynı anda birden çok isimli debug belirteci de kullanılabilir:
$ dmd deneme.d -ofdeneme -w -debug=ikili_arama -debug=yigin_yapisi
O durumda hem ikili_arama, hem de yigin_yapisi isimli debug blokları etkin olur.
debug(düzey)
Bazen debug belirteçlerine isimler vermek yerine, hata ayıklama düzeylerini belirleyen sayısal değerler verilebilir. Artan her düzey, daha derinlemesine bilgi verir:
debug import std.cstream; void birİşlev(string dosyaİsmi, int[] sayılar) { debug(1) dout.writefln("birİşlev işlevine girildi"); debug(2) { dout.writefln("işlev parametreleri: "); dout.writefln(" isim: ", dosyaİsmi); foreach (i, sayı; sayılar) { dout.writefln(" %4s: %s", i, sayı); } } // ... asıl işlemler ... }
Derleyiciye belirtilen debug düzeyi, o düzey ve daha düşük olanlarının etkinleşmesini sağlar:
$ dmd deneme.d -ofdeneme -w -debug=1 $ ./deneme birİşlev işlevine girildi
Daha derinlemesine bilgi almak istendiğinde:
$ dmd deneme.d -ofdeneme -w -debug=2 $ ./deneme birİşlev işlevine girildi işlev parametreleri: isim: deneme.txt 0: 10 1: 4 2: 100
version(isim), ve version(düzey)
version, debug olanağına çok benzer ve kod içinde aynı şekilde kullanılır:
version (denemeSürümü) /* ... bir ifade ... */; version (okulSürümü) { // ... okullara satılan sürümle ilgili ifadeler ... } version(1) birDeğişken = 5; version(2) { // ... sürüm 2 ile ilgili bir olanak ... }
Bütünüyle aynı şekilde çalışıyor olsa da, debug'dan farkı, program için farklı sürümler oluşturma amacıyla kullanılmasıdır.
Yine debug'da olduğu gibi, aynı anda birden fazla version bloğu etkinleştirilebilir:
$ dmd deneme.d -ofdeneme -w -version=kayit -version=hassas_hesap
Bazı version isimleri, programlarımızda yararlanabilmemiz için hazır olarak tanımlıdır:
| DigitalMars | Derleyici, Digital Mars'ınki |
| X86 | Intel veya AMD 32 bit işlemcisi |
| X86_64 | AMD veya Intel 64 bit işlemcisi |
| Windows | Microsoft Windows sistemi |
| Win32 | Microsoft 32 bit Windows sistemi |
| Win64 | Microsoft 64 bit Windows sistemi |
| linux | Bütün Linux sistemleri |
| Posix | Bütün Linux sistemleri |
| LittleEndian | Bayt sırası; düşük değerlinin önce olduğu durum |
| BigEndian | Bayt sırası; yüksek değerlinin önce olduğu durum |
| D_Coverage | İşletilen bütün kod satırlarını belirleyecek şekilde derleniyor (Code coverage analysis, -cov derleyici seçeneği |
| D_Ddoc | Ddoc belgeleri üretiliyor (-D derleyici seçeneği) |
| D_InlineAsm_X86 | X86 inline assembler'ı mevcut |
| D_InlineAsm_X86_64 | X86-64 inline assembler'ı mevcut |
| D_LP64 | Göstergeler 64 bitlik (-m64 derleyici seçeneği) |
| D_PIC | Position Independent Code üretiliyor (-fPIC derleyici seçeneği) |
| unittest | Birim testleri etkin (-unittest derleyici seçeneği) |
| D_Version2 | Bir D2 derleyicisi ile derlenmekte |
| none | Hiçbir zaman tanımlı değildir; kod bloğunu etkisizleştirir |
| all | Her zaman için tanımlıdır; none'ın tersidir |
O tanımlardan yararlanarak programınızın farklı olanaklarla derlenmesini sağlayabilirsiniz. Kullanım örneği olarak std.stream.Stream sınıfının bir işlevine bakalım:
void writeLineW(const(wchar)[] s) { writeStringW(s); version (Win32) writeStringW("\r\n"); else version (Mac) writeStringW("\r"); else writeStringW("\n"); }
O işlev; satır sonu için kullandığı karakterleri, üzerinde derlenmekte olduğu işletim sistemine göre seçmektedir.
debug'a ve version'a isim atamak
debug ve version'a sanki bir değişkenmiş gibi isim atanabilir. Değişkenlerden farklı olarak, atama işlemi değer değiştirmez, değer olarak belirtilen debug veya version isminin de etkinleşmesini sağlar.
import std.stdio; debug(hepsi) { debug = 1; debug = 2; version = denemeSürümü; version = okulSürümü; } void main() { debug(1) writeln("debug düzeyi 1"); debug(2) writeln("debug düzeyi 2"); version(denemeSürümü) writeln("deneme sürümü"); version(okulSürümü) writeln("okul sürümü"); }
Yukarıdaki koddaki debug(hepsi) bloğu içindeki atamalar, her satırda belirtilen ismin de etkinleşmesini sağlar. Böylece bu program için derleme satırında dört debug ve version seçeneği farklı olarak seçilebileceği gibi, -debug=hepsi kullanıldığında; 1, 2, denemeSürümü, ve okulSürümü sanki komut satırında bildirilmişler gibi etkinleşir:
$ dmd deneme.d -ofdeneme -w -debug=hepsi
$ ./deneme
debug düzeyi 1
debug düzeyi 2
deneme sürümü
okul sürümü
static if
Programın çalışması sırasındaki kararlarda çok kullandığımız if koşulunun derleme zamanındaki eşdeğeri static if'tir.
if koşulunda olduğu gibi, static if koşulu da bir mantıksal ifade ile kullanılır. static if bloğundaki kodlar bu mantıksal ifade true olduğunda derlenir ve programa dahil edilir, false olduğunda ise dahil edilmez. Yine if'e benzer şekilde, else static if ve else blokları da bulunabilir.
if'ten farklı olarak, mantıksal ifadenin sonucunun derleme zamanında bilinebiliyor olması şarttır.
static if her kapsamda kullanılabilir: modül dosyasında en üst düzeyde, yapı, sınıf, şablon, işlev, vs. kapsamlarında... Koşul sağlandığında, blok içindeki kodlar yazıldıkları satırda programa dahil edilirler.
Bir örnek olarak main içinde kullanalım:
import std.stdio; void main() { static if (char.sizeof == 1) { writeln("Merhaba dünya"); } else static if (char.sizeof == 2) { writeln("Selam dünya"); } else { writeln("Zaten beraberiz"); } }
char tek baytlık bir tür olduğu için, o program yalnızca "Merhaba dünya"lı satır yazılmış gibi derlenir:
import std.stdio; void main() { writeln("Merhaba dünya"); }
Çalışma zamanında hiçbir karşılaştırma yapılmaz.
static if zincirleri oluştururken else static if yazmak gerektiğine dikkat edin. Yanlışlıkla else if yazılmışsa, static if'in else bloğu olarak if kullanılacak demektir ve if de doğal olarak çalışma zamanında işletilecektir.
static if, çoğunlukla biraz aşağıda göreceğimiz is ifadesi ile kullanılır.
static assert
Aslında bir koşullu derleme olanağı olarak kabul edilmese de, static if'e benzerliği nedeniyle burada anlatmaya karar verdim.
Çalışma zamanında kullanmaya alıştığımız assert'le aynı şekilde, ama derleme zamanında işletilir. Mantıksal ifadesi false olduğunda derlemenin bir hata ile sonlandırılmasını sağlar.
static if gibi, static assert de programda herhangi bir kapsamda bulunabilir.
Örnek olarak, belirli bir algoritmanın yalnızca belirli büyüklükteki türlerle doğru olarak çalışabildiğini varsayalım. Bunu bir static assert ile şöyle denetleyebiliriz:
void birAlgoritma(T)(T değer) { // Bu algoritma, büyüklüğü dördün katı olan türlerle // çalışabilir static assert((T.sizeof % 4) == 0); // ... }
O işlev şablonu örneğin char ile çağrıldığında, programın derlenmesi bir hata ile sonlanır:
Error: static assert (1u == 0u) is false
Böylece algoritmanın uygunsuz bir türle kullanılmasının ve olasılıkla hatalı çalışmasının önüne geçilmektedir.
static assert de aşağıdaki is ifadesinden yararlanabilir.
is ifadesi
Bu ifade, daha önce null değeri ve is işleci dersinde 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 koşula bağlı olarak 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 kendisinin 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 tek başına örnekler bulmak oldukça zor. Bunun şablon parametrelerinde yararlı olacağını düşünebilirsiniz:
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ı şey } 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 dersinde gördüğümüz temel tür dönüşümlerini, veya Türeme dersinde 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'ten türemiş 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 işletilmektedir:
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 şu anahtar sözcükler kullanılabilir (bu anahtar sözcüklerden bazılarını daha sonraki derslerde anlatacağım):
structunionclassinterfaceenumfunctiondelegateconstimmutableshared
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"); } }
Böylece; o işlev şablonu, çağrıldığı türe göre değişik davranacak şekilde kodlanabilir. 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); birİşlev(HaftaGünleri.Pazartesi); const double sayı = 1.2; birİşlev(sayı); birİşlev(42);
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 tanımı |
|---|---|
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ü |
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: (in Object, in 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 (Tür isim : Belirteç, ŞablonParametreListesi)
is (Tür isim == Belirteç, ŞablonParametreListesi)
Bu iki kullanım, çok daha karmaşık ifadeler yazmaya olanak verir.
isim'den sonra kullanılan : ve == işleçleri, yukarıda gösterilen kullanımlarıyla aynı anlamdadır. Sırasıyla, o türe dönüşebilme ve aynı türden olma koşulunu denetlerler.
ŞablonParametreListesi, hem koşulun parçası olarak çalışır, hem de bütün koşul sağlandığında otomatik olarak uygun tür isimleri tanımlar. Bu, şablonlardaki tür çıkarsaması ile aynı şekilde çalışır.
Örnek olarak, indeks değeri string olan eşleme tabloları kullanıldığında bazı özel işlemler yapmak isteyelim. Yalnızca böyle türlere uymaya çalışan bir is ifadesi şöyle yazılabilir:
static if (is (T Değer : Değer[İndeks], İndeks : string)) {
Belirteç olarak Değer[İndeks] kullanılmış olması, şablon parametresi olan T'nin bir eşleme tablosu türü olmasını gerektirir. 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.
O koşulu kullanan ve dört farklı türle çağrılan bir program:
import std.stdio; void birİşlev(T)(T nesne) { writeln("\n--- ", T.stringof, " ile çağrıldık ---"); static if (is (T Değer : Değer[İndeks], İ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ı --- AssociativeArray!(string,int) ile çağrıldık --- Evet, koşul sağlandı değer türü : int indeks türü: string --- AssociativeArray!(string,double) ile çağrıldık --- Evet, koşul sağlandı değer türü : double indeks türü: string --- AssociativeArray!(long,dchar) ile çağrıldık --- Hayır, koşul sağlanmadı
D.ershane
Forum
Wiki
Projeler
Tanıtım
İletişim
Hakları