A Digitalmars D programozási nyelv

Típusok, típuskonstrukciók

Beépített típusok

Alaptípusok:

voidno type
bitsingle bit
bytesigned 8 bits
ubyteunsigned 8 bits
shortsigned 16 bits
ushortunsigned 16 bits
intsigned 32 bits
uintunsigned 32 bits
longsigned 64 bits
ulongunsigned 64 bits
centsigned 128 bits (reserved for future use)
ucentunsigned 128 bits (reserved for future use)
float32 bit floating point
double64 bit floating point
extendedlargest hardware implemented floating point size (Implementation Note: 80 bits for Intel CPU's)
imaginaryan extended floating point value, but with imaginary type
complextwo extended floating point values, one real and the other imaginary
charunsigned 8 bit ASCII
wcharunsigned Wide char (Implementation Note: 16 bits on Win32 systems, 32 bits on linux, corresponding to C's wchar_t type)

A bit adattípus speciális, egyetlen bináris bitet jelent. Pointerek vagy referenciák bitre nem megengedettek.

Származtatott beépített típusok
Deklarációk

A deklarációs szintaxisokat általában balról jobbra olvassuk:

int x; // x egy integer int* x; // x egy integerre mutató pointer int** x; // x egy olyan pointer, amely egy integerre mutató pointerre mutat int[] x; // x egy integerekből álló tömb int*[] x; // x egy integerekre mutató pointerekből álló tömb int[]* x; // x egy olyan pointer, ami egy integerekből álló tömbre mutat.

Ha a tömbök egymás mellett vannak, akkor jobbról balra olvassuk:

int[3] x; // x egy 3 integerből álló tömb int[3][5] x; // x egy 3 vektorból álló tömb, mely tömbök 5 integert tartalmaznak int[3]*[5] x; // x egy 5 pointerből álló tömb, ahol a pointerek 3 integerből álló tömbökre mutatnak.

Függvényekre mutató pointereket úgy kell deklarálni, mint az aldeklarációkat:

int (*x)(char); // x egy olyan függvényre mutató pointer, amelynek egy char argumentuma van és // a visszatérési értéke egy int típus int (*[] x)(char); // x egy olyan függvényekre mutató pointerekből álló tömb, amely függvényeknek // egy char argumentuma van és a visszatérési értékük egy int típus

C stílusú tömb-deklarációk, ahol a [] az azonosító jobb oldalán jelenik meg:

int x[3]; // x egy 3 elemű, integerekből álló tömb int x[3][5]; // x egy 3 vektorból álló tömb, mely tömbök 5 integert tartalmaznak int (*x[5])[3]; // x egy 5 pointerből álló tömb, ahol a pointerek 3 integert tartalmazó tömbökre mutatnak

Többszörös deklaráció esetén az összes deklarációnak típusa meg kell egyezzen:

int x,y; // x és y integerek int* x,y; // x és y integerre mutató pointerek int x,*y; // hibás, különböző típusok (x integer, y integerre mutató pointer) int[] x,y; // x és y integerekből álló tömbök int x[],y; // hibás, különböző típusok (x integerekből álló tömb, y integer)

Típusdefiníciók

Typedef típusdefiníciók

Új típust a 'typedef' kulcsszóval vezethetünk be. Az új, erős típus szemantikusan érthető lesz a típusellenőrző rendszer, a függvény felüldefiniálás és a debugger számára.

typedef int myint; void foo(int x) { . } void foo(myint m) { . } myint b; foo(b); // Ez a foo(myint) függvényt fogja meghívni.

A típusdefinícióval kezdeti értéket is specifikálhatunk, amely eltér az alaptípus kezdeti értékétől:

typedef int myint = 7; myint m; // kezdeti értéke 7 lesz
Alias típusok

Néha alkalmas lehet alias nevet használni egy típusra. A D-ben ezt alias deklarációval tehetjük meg:

alias abc.Foo.bar myint;

Az alias típusok szemantikusan azonosak azzal a típussal , amelyből képezték. A debbuger nem tudja megkülönböztetni ezeket, és nincs különbség itt a függvény-felüldefiniálás esetén sem. Például:

alias int myint; void foo(int x) { . } void foo(myint m) { . } hibás, a foo függvény többszörösen van definiálva

Az alias típusok ekvivalensek a C typedef-el.

Alias deklarációk

Egy szimbólumot deklarálhatunk egy másik szimbólum alias neveként. Például:

import string; alias string.strlen mylen; int len = mylen("hello"); // itt a string.strlen() függvény hívódik meg

A következő alias deklarációk érvényesek:

template Foo2(T) { alias T t; } instance Foo2(int) t1; // egy TemplateAliasDeclaration alias instance Foo2(int).t t2; alias t1.t t3; alias t2 t4; alias instance Foo2(int) t5; t1.t v1; // v1 típusa integer t2 v2; // v2 típusa integer t3 v3; // v3 típusa integer t4 v4; // v4 típusa integer t5.t v5; // v5 típusa integer

Az alias szimbólumokat gyakran használjuk olyankor, amikor egy hosszú szimbólumnevet akarunk lerövidíteni, vagy amikor az egyik szimbólum referenciáját akarjuk átirányítani egy másik szimbólumra.

version (Win32) { alias win32.foo myfoo; } version (linux) { alias linux.bar myfoo; }

Tömbök

A D nyelvben négyféle tömb típus van:

int* p; Adatra mutató mutató
int[3] s; Statikus tömb
int[] a; Dinamikus tömb
int[char[]] x; Asszociatív tömb
Mutatók
int* p;

Ezek egyszerű mutatók adatra, hasonlóan a C mutatókhoz. A mutatók arra szolgálnak, hogy C és specializált rendszerekkel kapcsolatot lehessen teremteni. Ezekhez nincs hossz információ társítva, és így nincs is lehetősége a fordítóprogram vagy a futtatási környezet számára, hogy indexelési határt vagy más memóriacímzési hibákat ellenőrizzen. A leggyakoribb használati esetekben ezeket a mutatókat helyettesíthetjük dinamikus tömbökkel, out és inout paraméterekkel és referencia típusokkal.

Statikus tömbök
int[3] s;

Ezek a C tömbökkel analóg módon használhatók. A statikus tömböket jellemzője, hogy fordítási időben ismert a méretük és nem is változtatható meg a továbbiakban.

Egy statikus tömb teljes mérete nem haladhatja meg a 16 Mb méretet. Amennyiben ennél nagyobb méretű tömbre van szükségünk, használjunk dinamikus tömböt.

Dinamikus tömbök
int[] a;

A dinamikus tömbök egy hossz értékből és egy adathalmaz mutatójából áll. Több dinamikus tömb is osztozhat az adathalmaz egy részén vagy egészén.

Deklarációk

Két módja van a tömbök deklarálásának: prefix és postfix. A prefix forma a javasolt, főleg abban az esetben, ha nem triviális típust deklarálunk.

Prefix Tömb deklarációk

A prefix deklarációk a deklarált azonosító előtt jelennek meg és jobbról balra olvashatók, azaz:

int[] a // egészek dinamikus típusa. int[4][3] b; // 3 olyan tömböt tartalmazó tömb, amelyek egyenként 4 egészet tartalmaznak. int[][5] c; // 5 egészeket tartalmazó dinamikus tömb tömbje. int*[]*[3] d; // 3 mutatót tartalmazó tömb, amelyek dinamikus tömbökre mutatnak, amelyek mutatókat tartalmaznak egészekre. int[]* e; // mutató dinamikus tömbre, amely egészeket tartalmaz.
Postfix Tömb deklarációk

A postfix deklarációk a deklarált azonosító után jelennek meg és balról jobbra olvassuk őket. Mindegyik csoport ekvivalens deklarációkat sorol fel:

// egészek dinamikus tömbje. int[] a; int a[]; // 3 olyan tömböt tartalmazó tömb, amelyek egyenként 4 egészet tartalmaznak. int[4][3] b; int[4] b[3]; int b[3][4]; // 5 dinamikus tömböt tartalmazó dinamikus tömb, ahol a dinamikus tömbök egészeket tartalmaznak. int[][5] c; int[] c[5]; int c[5][]; // tömb amely 3 dinamikus tömbre mutató mutatót tartalmaz. A dinamikus tömbök egészekre tartalmazó mutatókat tartalmaznak. int*[]*[3] d; int*[]* d[3]; int* (*d[3])[]; // egészek dinamikus tömbjére mutató mutató int[]* e; int (*e[]);

Indoklás: A postfix forma megegyezik azzal a móddal, ahogy tömböket C és C++ nyelveken deklaráljuk, ezáltal könnyebb tapasztalt C/C++ programozók számára a D nyelvre áttérés.

Használat

Két csoportba lehet sorolni a tömbökön végzett műveleteket - a tömb címén keresztül operáló műveletek, és a tömbök tartalmán keresztül operáló műveletek. A C csak a tömb címén keresztül tud operálni. A D nyelvben mindkettő mód használható.

A tömb címét a tömb neve határozza meg, mint a p, s vagy a:

int* p; int[3] s; int[] a; int* q; int[3] t; int[] b; p = q; // p és q ugyanarra mutat. p = s; // p az s tömb első elemére mutat. p = a; // p az a tömb első elemére mutat. s = ...; // hiba, mivel s egy fordítási időben meghatározott // statikus mutató egy tömbre. a = p; // hiba, mivel a tömb hossza amelyre a p mutat ismeretlen. a = s; // a az s tömbre fog mutatni. a = b; // a ugyanarra a tömbre mutat, amelyre b.
Szeletképzés

Egy tömb szeletelése azt jelenti, hogy egy altömbjét határozzuk meg. Egy tömbszelet esetén az adat nem másolódik le, csak egy másik referencia jön létre rá. Például:

int[10] a; // egy olyan tömb deklarálása, amely 10 egészet tartalmaz. int[] b; b = a[1..3]; // a[1..3] egy 2 elemet tartalmazó tömb, amely // a[1] és a[2] elemekből áll. foo(b[1]); // ekvivalens a foo(0) függvény hívással. a[2] = 3; foo(b[1]); // ekvivalens a foo(3) függvény hívással.

A [] egy rövidítése a teljes tömb szeletként kezelésére. Például, b tömb következő értékadásai szemantikailag mind megegyeznek:

int[10] a; int[] b; b = a; b = a[]; b = a[0 .. a.length];

A szeletelés nem csak azért hasznos, mert egy tömb részére hivatkozhatunk másik tömbként, hanem segítségével mutatókat indexhatár ellenőrzött tömbökké konvertálhatunk:

int* p; int[] b = p[0..8];

Bit tömbök szeletelése csak abban az esetben megengedett, ha a tömb alsó határa byte határra esik:

bit[] b; ... b[0..8]; // ok b[8..16]; // ok b[8..17]; // ok b[1..16]; // hiba, az alsó határ nem byte határra esik.

Bit tömbök esetén a rossz szelet hivatkozási kísérlet futási időben ArrayBoundsError kivételt vált ki.

Másolás

Amikor egy szelet operátor egy értékadás balértékeként jelenik meg egy kifejezésben, azt jelenti, hogy a tömb tartalma a célterület, nem pedig a tömb referenciája. A tömb másolás akkor történik, amikor a balérték egy szelet, és a jobbérték egy tömb vagy egy mutató amely ugyanolyan típusra mutat.

int[3] s; int[3] t; s[] = t; // a t[3] 3 eleme átmásolódik s[3] -ba. s[] = t[]; // a t[3] 3 eleme átmásolódik s[3] -ba. s[1..2] = t[0..1]; // ugyanaz, mint s[1] = t[0] s[0..2] = t[1..3]; // ugyanaz, mint s[0] = t[1], s[1] = t[2] s[0..4] = t[0..4]; // hiba, csak 3 elem van az s tömbben. s[0..2] = t; // hiba, a bal és a jobb érték mérete különbözik.

Az egymást átfedő területek másolása hiba:

s[0..2] = s[1..3]; // hiba, egymást átfedő területek s[1..3] = s[0..2]; // hiba, egymást átfedő területek

Azáltal, hogy megtiltjuk az egymást átfedő területek másolását lehetővé válik sokkal agresszívebb párhuzamos kód optimalizáció, mint amit a C soros szemantikája lehetővé tesz.

Értékadás

Ha egy szelet operátor szerepel egy értékadás bal értékeként, és a jobbérték típusa megegyezik a balérték elemtípusával, akkor a bal oldal minden elemének értékül lesz adva a jobboldal.

int[3] s; int* p; s[] = 3; // ugyanaz, mint s[0] = 3, s[1] = 3, s[2] = 3 p[0..2] = 3; // ugyanaz, mint p[0] = 3, p[1] = 3
Összefűzés

A ~ bináris operátor az összefűző operátor. Arra használt, hogy tömböket fűzzünk össze:

int[] a; int[] b; int[] c; a = b ~ c; // Létrehoz egy tömböt a b és c tömbök összefűzésével.

Sok nyelv a + operátort terheli túl, hogy összefűzésre használja. Ez félreértésekhez vezethet:

"10" + 3

Az előző kifejezés 13 értékű számot vagy a vagy a "103" értékű karakterláncot adja eredményként? nem egyértelmű, és a nyelv tervezők körültekintően szabályokat határoznak meg, hogy hogyan kell értelmezni - szabályok, amelyek hibásan kerülnek implementálásra, elkrülik a figyelmünket, elfelejtődnek és figyelmen kívül hagyásra kerülnek. Sokkal jobb, hogy van egy + operátor, amely az összeadást jelenti, és egy külön operátor a tömbök összefűzésére.

Hasonlóan, a ~= operátor összefűzést jelent:

a ~= b; // a az a és b összefűzésével keletkező tömböt fogja értékül kapni.

Az összefűzés mindig létrehoz egy másolatot az operandusaiból, akkor is ha az egyik operandus egy 0 hosszúságú tömb, azaz:

a = b; // a a b tömbre hivatkozik. a = b ~ c[0..0]; // a a b tömb egy másolatára hivatkozik.
Műveletek

Általánosságban, az (a[n..m] op e) úgy definiált, mint:

for (i = n; i < m; i++) a[i] op e;

Azaz a következő kifejezés:

a[] = b[] + 3;

eredmény szempontjából ekivalens a következő kóddal:

for (i = 0; i < a.length; i++) a[i] = b[i] + 3;

Amikor több mint egy [] operátor jelenik meg a kifejezésben, akkor az átaluk repreznetált tartományok méretének meg kell egyeznie.

a[1..3] = b[] + 3; // hiba, 2 elem nem ugyannyi, mint 3 elem.

Példák:

int[3] abc; // 3 egészet tartalmazó statikus tömb int[] def = [ 1, 2, 3 ]; // 3 egészet tartalmazó dinamikus tömb void dibb(int *array) { array[2]; // ugyanazt jelenti, mint *(array + 2) *(array + 2); // a 2-ik elemet kérdezzük le } void diss(int[] array) { array[2]; // ok *(array + 2); // hiba, a tömb nem egy mutató } void ditt(int[3] array) { array[2]; // ok *(array + 2); // hiba, a tömb nem egy mutató }
Többdimenziós tömbök

Tapasztalt FORTRAN numerikus programozók tudják, hogy egy többdimenziós négyzetes tömb olyan dolgokhoz, mint mátrix műveletek, sokkal gyorsabbak elérés szempontjából, mint olyan adatszerkezeten keresztül, ahol több egydimenziós tömbre mutató mutatókat csoportosítunk egy egydimenziós tömbbe.

double[][] matrix;

Az előző kód egy olyan tömböt hoz létre, amelynek elemei mutatók egydimenziós tömbökre. (A dinamikus tömbök egy adatvektorra mutató mutatóval vannak megvalósítva.) Mivel ezek a tömbök változó méretűek lehetnek (mivel dinamikusan méretezhetők), ez néha "kesztyűszerű" tömbnek van nevezve. A kód optimalizáció szempontjából még rosszabb, hogy a sorok néha egymásra is mutathatnak. Szerencsére a D rendelkezik statikus tömbökkel, amelyek bár ugyanazt a szintaktikát használják, fix négyzetes elhelyezéssel vannak megvalósítva.

double[3][3] matrix;

Az előző kód olyan négyzetes mátrixot hoz létre, amely 3 sort és 3 oszlopot tartalmaz, folyamatosan elhelyezve a memóriában. Más nyelvekben, ezt többdimenziós tömbnek hívják és a következőképpen lehet deklarálni:

double matrix[3,3];
Attribútumok

A statikus tömbök tulajdonságai a következők:

.sizeof A tömb hosszának és az egyes elemek byte-ban mért méretének szorzatát adja vissza.
.length Visszaadja a tömbben található elemek számát. Ez egy fix érték statikus tömbök esetén.
.ptr Visszaadja a tömb els? elemére mutató mutatót.
.dup Létrehoz egy dinamikus tömböt a tömbbel megegyez? méretben, és az adatokat átmásolja bele.
.reverse Helyben megfordítja a tömböt. A tömböt adja vissza.
.sort Helyben rendezi a tömböt. A tömböt adja vissza.

A dinamikus tömbök tulajdonságai a következők:

.sizeof Visszaadja a dinamikus tömb referenciájának méretét, ami 8 egy 32 bites gépen.
.length Lekérdezi/beállítja az elemek számát a tömbben.
.ptr Visszaadja a tömb els? elemére mutató mutatót.
.dup Létrehoz egy dinamikus tömböt a tömbbel megegyez? méretben, és az adatokat átmásolja bele.
.reverse Helyben megfordítja a tömböt. A tömböt adja vissza.
.sort Helyben rendezi a tömböt. A tömböt adja vissza.

Példák:

p.length // hiba, a "length" nem ismert a mutatók esetében s.length // fordítási időbeli konstans (3) a.length // futás idejű változó p.dup // hiba, "length" nem ismert s.dup // létrehoz egy 3 elemű tömböt és átmásolja s elemeit bele a.dup // létrehoz egy a.length méretű tömböt, és a elemeit átmásolja bele.
Dinamikus tömbök újraméretezése

A dinamikus tömbök .length tulajdonsága állítható az = operátor balértékeként.

array.length = 7;

Ez azt eredményezi, hogy a tömb reallokálásra kerül, és a jelenlegi tartalom az új tömbbe lesz másolva. Amennyiben az új tömb mérete kisebb, akkor csak annyi elem lesz lemásolva, amennyi még elfér benne. Amennyiben a tömb mérete nagyobb, akkor a maradék elemek az elem típusának alapértelmezett módján lesz inicializálva.

A hatékonyság növelésének érdekében, futási időben mindig helyben próbáljuk a tömb méretét megnövelni, hogy elkerüljük az extra másolásokat. Mindig másolás lesz, ha az új méret nagyobb mint az eredeti és a tömböt nem a new operátorral allokáltuk vagy nem egy előző átméretezéssel hoztuk létre.

Ez azt jelenti, hogy egy tömbszelet, amely közvetlenül követi az átméretezett tömböt, akkor az átméretezett tömb elfedheti a szeletet, vagyis:

char[] a = new char[20]; char[] b = a[0..10]; char[] c = a[10..20]; b.length = 15; // mindig helyben lesz átméretezve, mert b a[] egy szelete, //amelynek van elég memóriája 15 char elemre. b[11] = 'x'; // a[15] és c[5] szintén érintett az értékadás által a.length = 1; a.length = 20; // nincs valódi változás a memória elhelyezésben c.length = 12; // mindig másol, mert c[] nem egy gc allokált blokk kezdetén van c[5] = 'y'; // nem érinti az a[] vagy b[] tartalmát. a.length = 25; // lehet, hogy másol, de lehet hogy nem a[3] = 'z'; // vagy érinti vagy nem b[3] értékét, amelyet még mindig //átfed a régi a[3]

Ahhoz, hogy garantáljuk a másolást, használjuk a .dup tulajdonságot, hogy biztosak legyünk benne, hogy a tömb átmérezhető.

Ezek a szempontok szintén érvényesülnek a tömbök összefűzésénél a ~ és ~= operátorok segítségével.

Egy dinamikus tömb átméretezése egy viszonylag költséges művelet. Ezért, bár a következő módja a tömb feltöltésének működik, nem lesz túl hatékony:

int[] array; while (1) { c = getinput(); if (!c) break; array.length = array.length + 1; array[array.length - 1] = c; }

Egy sokkal praktikusabb megközelítés minimalizálja az átméretezések számát:

int[] array; array.length = 100; // tipp for (i = 0; 1; i++) { c = getinput(); if (!c) break; if (i == array.length) array.length = array.length * 2; array[i] = c; } array.length = i;

Egy jó kezdőérték megtippelése művészet, de egy olyat könnyű, amely az esetek 99%-át fedi. Például, ha a felhasználótól parancssorból várunk bemenetet, akkor nem valószínű, hogy 80 karakternél hosszabb lesz.

Határ ellenőrzés

Egy tömböt nullánál kisebb vagy a tömb méretével megegyező vagy nagyobb értékkel indexelni hiba. Amennyiben az index az indexhatárokon kívülre esik, akkor egy ArrayBoundsError kivétel keletkezik, ha futási időben derül ki a hiba, illetve fordítási időben szintaktikai hiba lesz. Egy program nem építhet arra, hogy az indexhatárok ellenőrzése megtörténik, vagyis a következő program hibás:

try { for (i = 0; ; i++) { array[i] = 5; } } catch (ArrayBoundsError) { // a ciklus befejezése }

A ciklus helyesen:

for (i = 0; i < array.length; i++) { array[i] = 5; }

Implementációs megjegyzés: A fordítóprogramnak kísérletet kell tennie arra, hogy fordítási időben felderítse az indexhatárokon túli indexelést, például:

int[3] foo; int x = foo[3]; // hiba, túlindexelés

Az indexhatárokat futási időben ellenőrző kódrészlet beillesztése ki- és bekapcsolható fordítási időben egy kapcsolóval.

Inicializálás
Alapértelmezett inicializálás
Üres inicializálás

Üres inicializálás akkor történik, ha az Initializer egy tömb számára void. Ez azt jelenti, hogy nincsen inicializálás, tehát a tömb tartalma ismeretlen lesz. Ez mindössze optimalizáció szempontjából hasznos. Az üres inicializálás egy haladó technika és csak akkor célszerű használni, ha a kód futásának megfigyelése során jelentős sebességnövekedés várható tőle.

Statikus inicializálás és statikus tömbök
int[3] a = [ 1:2, 3 ]; // a[0] = 0, a[1] = 2, a[2] = 3

Ez leginkább akkor hasznos, ha a tömb indexek felsorolással vannak megadva:

enum Color { red, blue, green }; int value[Color.max + 1] = [ blue:6, green:2, red:5 ];

Amennyiben bármelyik tagja a tömbnek inicializálva van, akkor az összeset inicializálni kell. Ez azért szükséges, hogy az olyan tipikus hibák kiküszöbölésre kerüljenek, mint a felsorolási típus új értékkel kerül kiegészítésre, de nem lesz inicializálva a tömbben az új tag.

Speciális tömbök
Bittömb

Bit vektor a következő módon hozható létre:

bit[10] x; // 10 bit tömbje

A tároláshoz szükséges memóriaméret implementáció függő. Implementációs megjegyzés: Intel CPU-kon ez az érték fel lesz kerekítve a következő 32 bit méretre.

x.length // 10, a bitek száma x.size // 4, a tároláshoz szükséges byte-ok mennyisége

Azaz a méret osztva az elemek számával nem ugyanaz, mint a (x.size / x.length) kifejezés értéke.

Asszociatív tömbök

A D nyelv egyik újdonsága az asszociatív tömb. Az asszociatív tömböknek van indexük, de ennek nem kell feltétlenül integernek lennie, és maga a tömb lehet hézagos. Egy asszociatív tömb indexét kulcs-nak nevezzük.

Asszociatív tömböt úgy kell deklarálni, hogy a kulcs típusát [] között adjuk meg.

int[char[]] b; // a b egy integerekből álló asszociatív tömb, melynek elemei karakterekből álló // vektorokkal vannak indexelve b["hello"] = 3; // a "hello" kulcsú (indexű) elem értékét 3-ra állítja func(b["hello"]); // a func() függvény meghívása a 3 paraméterrel

A delete operátorral lehet törölni elemet az asszociatív tömbből:

delete b["hello"];

Ez nem a b["hello"] tartalmát törli, hanem a "hello" kulcsot az asszociatív tömbből!

Az InExpression mező egy logikai értéket ad vissza, aszerint hogy egy kulcs eleme-e egy asszociatív tömbnek vagy nem:

if ("hello" in b)

Függvény vagy void nem lehet típusa egy kulcsnak.

Típuskonverziók

Pointer konverzió

Pointerek átkonvertálása nem pointerekké és fordítva a D-ben nem megengedett. Ez megakadályozza, hogy pointereket úgy kezeljünk, mintha integerek lennének, mivel ez a fajta használat nagy zavart tud okozni a szemétgyűjtésben és a kód egyik gépről a másik gépre való átvitelében. Ha valóban erre lenne szükségünk, alkalmazzuk az union-t, ennek ellenére legyünk óvatosak, hogy a szemétgyűjtésben ne okozzon kárt.

Implicit konverzió

A D-ben sok típus van, beépítettből és deriváltból egyaránt. Fárasztó lenne minden típuskonverziót külön kérni, így az implicit konverziós lépések automatikusan hajtódnak végre.

Egy typedef típus implicit konverzióval képződik le az alapját képező típusra, minden más esetben explicit konverzió szükséges. Például:

typedef int myint; int i; myint m; i = m; // OK m = i; // HIBA m = (myint)i; // OK

A következő típusok impliciten konvertálódnak át int típusúvá:

A typedef-el definiált típusok átkonvertálódnak az alapjukat képező típusokra.

Szokásos aritmetikai konverziók

A szokásos aritmetikai konverziók a bináris operátorok operandusait átkonvertálják egy egyszerű típussá. Az operandusoknak aritmetikai típusúaknak kell lenniük. A következő szabályok kerülnek alkalmazásra:

  1. A typedef-el definiált típusok átkonvertálódnak az alapjukat képező típusokra.
  2. 2. Ha az egyik operandus kiterjesztett, akkor a másik operandus is átkonvertálódik kiterjesztett típussá.
  3. 3. Ha az egyik operandus double típusú, akkor a másik operandus is átkonvertálódik double-re.
  4. 4. Ha az egyik operandus float, akkor a másik operandus is átkonvertálódik float-ra.
  5. 5. Ezután minden integerre a következők lesznek érvényesek:
    1. 1. Ha mindkettő ugyanolyan típusú, akkor nem konvertálódik tovább.
    2. 2. Ha mindkettő signed vagy unsigned, akkor a kisebb típus átkonvertálódik a nagyobb típusra.
    3. 3. Ha a signed típus nagyobb, mint az unsigned típus, akkor az unsigned típus konvertálódik át signed típusra.
    4. 4. A signed típus átkonvertálódik az unsigned típusra.

Delegátorok

A D-ben nincs lehetőség arra, hogy egy pointer egy tagra mutasson, viszont egy hasznosabb elképzelést - amelyet delegátornak nevezünk - támogat a nyelv. A delegátor két adat aggregációját jelenti: egy objektum-referencia és egy függvény-pointer társítását. Az objektum-referencia formálja a this pointert amikor a függvény meghívódik.

A delegátor deklarációja hasonló a függvény-pointerhez, azzal a különbséggel, hogy a 'delegate' kulcsszót kell használni a 'function' helyett:

int function(int) fp; // fp egy függvényre mutató pointer int delegate(int) dg; // dg egy delegátor egy függvényre

Egy delegátor inicializálása hasonlóan történik, mint a függvény-pointereknél:

int func(int); fp = &func; // fp a func-ra mutat class OB { int member(int); } OB o; dg = &o.member; // dg egy delegátor az o objektumra és // a függvény member tagjára

Egy delegátort nem lehet inicializálni statikus függvénytaggal vagy nem függvénytaggal.

Egy delegátort a függvény-pointerekhez hasonló módon lehet meghívni:

fp(3); // func(3) hívása dg(3); // o.member(3) hívása

A delegátok a tagfüggvényekre való hivatkozáson kívül általánosabb módon is használhatók, melyről bővebben a Függvények és delegátok részben írunk.

Tulajdonságok

Minden adattípus és kifejezés rendelkezik néhány beépített tulajdonsággal, amelyeket le lehet kérdezni:

Beépített adatok tulajdonságai
.init kezdeti érték (0) .size méret byte-okban .max max. érték .min min. érték .sign előjel
Lebegőpontos típusok tulajdonságai
.init kezdeti érték (NaN) .size méret byte-okban .infinity végtelen érték .nan NaN érték .sign 1 ha negatív, 0 ha pozitív .isnan 1 ha nan, 0 különben .isinfinite 1 ha +- végtelen, 0 különben .isnormal 1 ha nem nan vagy végtelen, 0 különben .digits tizedesjegyek száma .epsilon legkisebb növelés .mantissa mantissza bitjeinek száma .maxExp max. 2 hatvány kitevője .max legnagyobb reprezentálható érték, ami még nem végtelen .min legkisebb reprezentálható érték, ami még nem 0
Az .init tulajdonság

Az .init egy konstans kifejezést eredményez, ami kezdő érték lesz. Ha az .init-et egy típusnál alkalmazzuk, akkor ez lesz a kezdőértéke a típusnak. Ha változó vagy mező esetén használjuk, akkor a kifejezés a változó vagy mező kezdőértéke lesz. Például:

int a; int b = 1; typedef int t = 2; t c; t d = cast(t)3; int.init // 0 lesz a.init // 0 lesz b.init // 1 lesz t.init // 2 lesz c.init // 2 lesz d.init // 3 lesz struct Foo { int a; int b = 7; } Foo.a.init // 0 lesz Foo.b.init // 7 lesz
Tömbök tulajdonságai

Statikus tömbök:

.sizeof A tömb hosszának és az egyes elemek byte-ban mért méretének szorzatát adja vissza.
.length Visszaadja a tömbben található elemek számát. Ez egy fix érték statikus tömbök esetén.
.ptr Visszaadja a tömb els? elemére mutató mutatót.
.dup Létrehoz egy dinamikus tömböt a tömbbel megegyez? méretben, és az adatokat átmásolja bele.
.reverse Helyben megfordítja a tömböt. A tömböt adja vissza.
.sort Helyben rendezi a tömböt. A tömböt adja vissza.

Dinamikus tömbök:

.sizeof Visszaadja a dinamikus tömb referenciájának méretét, ami 8 egy 32 bites gépen.
.length Lekérdezi/beállítja az elemek számát a tömbben.
.ptr Visszaadja a tömb els? elemére mutató mutatót.
.dup Létrehoz egy dinamikus tömböt a tömbbel megegyez? méretben, és az adatokat átmásolja bele.
.reverse Helyben megfordítja a tömböt. A tömböt adja vissza.
.sort Helyben rendezi a tömböt. A tömböt adja vissza.

Asszociatív tömbök:

sizeof Visszaadja az asszociatív tömb méretét, ami tipikusan 8 hosszú.
length Visszaadja a tömbbeli elemek számát. A dinamikus tömbökkel ellentétben ez csak olvasható.
keys Egy dinamikus tömböt ad vissza, melynek elemei az asszociatív tömb kulcsai lesznek.
values Egy dinamikus tömböt ad vissza, melynek elemei az asszociatív tömb elemei lesznek.
rehash Átalakítja az asszociatív tömböt úgy, hogy a keresés hatékonyabb legyen. Hasznos például akkor, amikor egy program megtölti a szimbólumtáblát, és most sürg?sen meg kell keresnie benne egy adatot. A rehash az átalakított tömbre ad egy referenciát eredményül.