Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Godny następca C i C++, czyli programowanie w D - cz. 3: Tablice

Po dwóch poprzednich wpisach o języku programowania D przyszedł czas na kolejny. Tym razem opiszę, jak w D wyglądają tablice. Choć takie funkcje, jak tablice dynamiczne i asocjacyjne pojawiają się w wielu innych językach programowania (czasem pod postacią map lub wektorów), w D rozwiązano tą sprawę trochę inaczej, niż w C++.

Wskaźniki

Chociaż w D występują wskaźniki, nie ma potrzeby ich używania. Zachowane zostały wyłącznie w celu zapewnienia kompatybilności binarnej z C. W większości wypadków tablice dynamiczne oraz inne elementy D w pełni zastępują wykorzystanie wskaźników.

Tablice statyczne

O tym rodzaju tablic nie ma sensu zbytnio się rozpisywać, ponieważ są one bardzo dobrze znane z C/C++. Ich długość musi być znana już w czasie kompilacji.

r   e   k   l   a   m   a

Tablice statyczne możemy deklarować na dwa sposoby:


int tab1[10]; // sposób znany z C
int[10] tab2; // sposób znany np. z Javy

Tablice dynamiczne

Kolejnym typem tablic dostępnych w D są tablice dynamiczne. W odróżnieniu od statycznych mogą one zmieniać swój rozmiar. W wielu językach ta funkcjonalność dostępna jest przy użyciu wektorów. Rozwiązanie zastosowane w D jest jednak prostsze i bardziej czytelne.

Deklaracja tablic dynamicznych przebiega identycznie, jak w wypadku tablic statycznych z tą różnicą, że w nawiasach kwadratowych nie podajemy rozmiaru:


int tab1[];
int[] tab2;

Operacje na tablicach dynamicznych

D umożliwia również proste wykonywanie różnych operacji na tablicach:
- zmiana długości - aby zmienić długość tablicy dynamicznej w D, należy ustawić wartość length:


int[] tablica;
tablica.length = 10;

- łączenie - wiele języków przeciąża operator "+" do łączenia tablic. W D wykorzystywany jest znak tyldy (~), co niestety może być pewną niedogodnością podczas pisania na Windowsie (ze względu na utrudnione wprowadzanie tego znaku). Można też użyć operatora ~=. Wygląda to w ten sposób:


int[] tab1;
int[] tab2;
int liczba;
tab1.length = 10; // Ustawiamy długość na 10
tab2 = tab1 ~ liczba; //przepisuje tab1 do tab2, następnie zwiększa długość o 1 i dopisuje liczbę na końcu
tab2 ~= tab1; // Dopisuje tab1 do tab2

- wycinki - pozwalają operować na fragmentach tablicy. Tworzą wyłącznie referencje, nie kopiują danych.


int[] a;
a.length = 10;
int[] b = a[2..5]; //tablica b składa się z elementów a[2], a[3] i a[4]

- kopiowanie - następuje wtedy, gdy zarówno po lewej, jak i po prawej stronie znaku '=' umieścimy wycinek:


int[] a, b;
a.length = 10;
b.length = 5;
a[2..5] = b[0..3];
a[0..3] = a[6..9];

Możliwe jest kopiowanie w obrębie jednej tablicy, pod warunkiem, że fragmenty są tej samej długości i nie zachodzą na siebie.
- operacje arytmetyczne - kolejna sprytna opcja. W D wykonanie tej samej operacji arytmetycznej na wszystkich elementach tablicy nie wymaga użycia pętli:


int[] array;
array.length = 10;
array[] += 5;

- pozostałe - Tablice w D udostępniają komendy odpowiedzialne za sortowanie i odwracanie kolejności elementów w miejscu. Możemy również pobrać długość tablicy.


int dlugosc = array.length;
array.sort;
array.reverse;

Oczywiście do działania opcji sort musi istnieć możliwość porównywania dla danego typu. W przypadku liczb, znaków itp. nie musimy się martwić, ale w celu sortowania tablic obiektów własnych klas musimy własnoręcznie zaimplementować porównywanie.

Kontrola indeksów

D kontroluje również rozmiary tablic. W przypadku próby przekroczenia rozmiaru tablicy statycznej program zgłosi błąd w trakcie kompilacji. W wypadku tablic dynamicznych zostanie zgłoszony wyjątek ArrayBoundsError, który możemy przechwycić za pomocą bloku try/catch.

Tablice asocjacyjne

Tablice asocjacyjne są to tablice, których indeksy niekoniecznie są liczbami. Indeks takiej tablicy zwany jest kluczem. Tablice asocjacyjne w wielu językach dostępne są jako mapy. W D nie wymagają wykorzystywania specjalnych stworzonych w tym celu klas. Podstawowe operacje na tablicach asocjacyjnych wyglądają następująco:


double[string] array; // deklarujemy tablicę
array["maslo"] = 1.99; // dodajemy element o indeksie "maslo"
array["batonik"] = 1.49;
zaplac(array["batonik"]); // zaplac(1.49);    10.05 -> poprawiłem literówkę.
array.remove("batonik"); // usuwamy element o indeksie "batonik"

Na koniec - jak obiecałem - przykład prostego słownika:

import std.stdio;

void main()
{
	string[string] words;  // Deklarujemy tablicę słówek. Indeksy będą ciągami znaków.
	words["ser"] = "cheese";  // Słowom polskim przyporządkowujemy angielskie.
	words["mleko"] = "milk";
	words["maslo"] = "butter";
	words["jajko"] = "egg";
	
	write("Podaj słowo: ");  // Prosimy o wprowadzenie słowa
	string key = readln[0..$-1];
/*Wczytujemy słowo. Wycinek [0..$-1] obetnie ostatni znak wczytanego ciągu znaków (zatwierdzenie enterem umieści tu łamanie wiersza)*/
	try
	{
		writeln(key ~ " - " ~ words[key]);
/*Wypisujemy słówko z przetłumaczeniem. Używamy operatora ~ do połączenia ciągów znaków w jeden. Alternatywnie można użyć przecinka.*/
	}
	catch(core.exception.RangeError err)
/*Jeżeli nie będzie podanego klucza w tablicy, program wyrzuci wyjątek RangeError. Musimy go obsłużyć*/
	{
		writeln("Nie znam takiego slowa.");
	}
	readln(); // Zapobiegamy natychmiastowemu zniknięciu konsoli.
}

Koniec części trzeciej

Choć i tutaj D nie wprowadza jakiejś niesamowitej rewolucji, tablice wydają się być bardziej uporządkowane i znacznie prostsze w użyciu. To wszystko sprawia, że D jest przede wszystkim językiem bardzo wygodnym.

Część pierwsza, druga, trzecia... troszkę już się uzbierało. "Mody na sukces" co prawda liczbą odcinków nie pobiję, ale jeszcze czwarty z pewnością się pojawi. Pokażę w nim programowanie kontraktowe i testy jednostokowe, czyli jak program może sam się przetestować. Zapraszam niebawem. 

Komentarze