Poradniki

 
 
 
Kurs programowania w RGSS/Ruby - część 2
(Shlizer)

W dzisiejszej części kursu przybliżę Wam sekrety programowania obiektowego oraz tajniki stałych, zmiennych, a także operacji na tychże.

Rodzaje programowania
Zasadniczo w programowaniu mamy do czynienia z trzema paradygmatami programowania: strukturalnym, proceduralnym oraz obiektowym. Pierwszy z nich cechuje się kodem pisanym i przetwarzanym przez interpreter lub kompilator ciurkiem. Tak jak my czytamy książkę linia po linii, tak program wykonuje się w ten sam sposób. W tym rodzaju programowania dopuszczalne są pętle, ale z kolei nie powinno się używać poleceń, które powodują skok do innych partii kodu (goto, break, continue, next itd.). Programowanie strukturalne często jest wykorzystywane w pisaniu bardzo prostych programów, jak np. obliczenie długości pola trójkąta odcinka o wpisanych przez użytkownika parametrach.
Drugi paradygmat, czyli programowanie proceduralne skupia się na tworzeniu procedur (lub w niektórych językach programowania – funkcji). W samym kodzie owe procedury wykonują ściśle określone obliczenia i dają wynik końcowy, który dalej w kodzie może być używany. Tego typu programowanie jest wciąż dobre do mniejszych programów, w których często wykonywane są jakieś czynności. W ten sposób napiszemy przykładowo kalkulator.
Ostatni paradygmat to programowanie obiektowe, w którym kod definiowany jest za pomocą obiektów. Mówi się, że jest to najłatwiejszy do zrozumienia rodzaj programowania, bo jest podobny do postrzegania świata przez ludzki mózg. W programowaniu obiektowym występują klasy oraz ich obiekty, które wykonują zadania na rzecz innych obiektów lub całego programu. O tym programowaniu więcej dowiemy się w kolejnym rozdziale.
Zasadniczo wiele skryptów da się napisać na wszystkie trzy sposoby – pozostaje jednak kwestia ilości obliczeń (a zatem i czasu wykonania kodu) oraz ilości tekstu, który programista musi napisać, aby program działał zgodnie z założeniami. Istotną rzeczą jest fakt, iż powszechnie piętnowane jest mieszanie tych rodzajów programowania. Kod, który jest w połowie napisany proceduralnie i w połowie obiektowo uważany jest za błędny lub co najmniej niesmaczny w kwestii programowania.

Wszystko jest obiektem
Ruby jest językiem obiektowym, jak już wspomniałem w poprzedniej części poradnika. Prawdę mówiąc jest on wyjątkowy z tego względu, że nie ma możliwości pisania w nim kodu stricte strukturalnego ani proceduralnego, jak w innych językach - co za tym idzie wszystko, co jest w nim napisane jest obiektem.
Zacznijmy jednak od podstaw obiektowości – klasy i obiektu. Klasa to abstrakcyjny twór, opisujący jakąś strukturę. Obiekt natomiast to fizyczne przedstawienie klasy. Przykładowo – klasą może być człowiek, natomiast obiektem – każde fizyczne przedstawienie tej klasy, czyli ja, Ty, pani od matematyki albo kierowca w autobusie.
Każde z nas ma jakieś cechy wspólne, które mimo wszystko nas odróżniają (jak waga, wzrost, wiek). Każde z nas potrafi także wykonywać różne czynności (jak jeść, rosnąć, czy oddychać). W programowaniu obiektowym cechy obiektu nazywają się polami (lub mniej poprawnie, z języka strukturalnego – zmiennymi), natomiast wszelkie czynności wykonywane przezeń to metody (mniej poprawnie – funkcje bądź procedury).
Poniższy kod przedstawia na przykładzie to, co przed chwilą omówiliśmy, czyli klasę człowiek oraz stworzenie jej obiektu – konkretną istotę.

{} Listing 2.1 class Czlowiek def initialize @waga = 70 @wzrost = 180 @wiek = 18 end def jedz end def rosnij end def oddychaj end end Czlowiek.new
Wygląda strasznie, prawda? Po kolei przyjrzyjmy się co ten kod nam prezentuje. W linijce #1 ustalamy jak nasza klasa będzie się nazywać. Każdą definicję naszego abstrakcyjnego tworu zaczynamy od słówka kluczowego 'class'. Proste, prawda? Wszystko, co odnosi się do danej klasy zawarte jest w bloku między słowami 'class' oraz 'end'. Na naszym przykładzie definicja kończy się wraz z tym drugim słówkiem w linii #16.

Ważne!
Istnieje wiele słów kluczowych (np. class, module, for, if, case), które wymagają domknięcia słówkiem 'end'. Oba słówka – zaczynające i kończące to tak zwane klamry blokowe, które oddzielają dany blok od innego. Pomyślcie o tym jak o pudełkach – mamy pudełko klasy, do którego wkładamy pudełko metody (funkcji), a to pudełko posiada np. dwa pudełka warunkowe (if). Proste, prawda? =)


Każdą metodę klasy zaczynamy od słówka kluczowego 'def' i kończymy tak samo, jak poprzednio. Tak, jak widzicie mamy już gotowe definicje metod jedzenia, rośnięcia i oddychania. Choć są one rozpoznawane przez obiekt klasy, to nie robią nic, ponieważ ich wnętrze jest puste – program nie wykonuje żadnych czynności po wywołaniu tych metod.
Przyjrzyjmy się jednak pierwszej z nich, która przykuwa uwagę – 'initialize'. Jest to metoda specjalna (w niektórych językach mogą występować też inne nazwy, np. PHP mówi się o niej metoda magiczna), która wywoływana jest tylko raz w trakcie życia danego obiektu, na samym jego początku. Innymi słowy, za każdym razem, gdy stworzymy jakikolwiek obiekt klasy człowiek będziemy automatycznie wywoływać 'initialize'. Z uwagi na jej specjalną funkcję, w programowaniu obiektowym taki twór nazywamy konstruktorem danej klasy, ponieważ wywołuje się przy konstrukcji obiektu danej klasy.
W ostatniej linijce listingu 2.1 tworzymy nowy obiekt klasy Czlowiek poprzez wywołanie jego metody 'new'. Tej metody nie musimy tworzyć – posiada go każda napisana klasa.

Ważne!
Pamiętaj o tym, aby w nazwach klas, metod (funkcji), a także wszelkich pól (zmiennych) i stałych unikać polskich znaków. Interpreter Ruby może zwracać błąd lub działać niepoprawnie jeśli któraś z tych nazw będzie zawierać polskie kreski, kropki i ogonki przy literach.

Zmienna zmienna i prawie stała stała
No dobrze – stworzyliśmy obiekt klasy Czlowiek. Jednak, aby móc z nim cokolwiek zrobić w późniejszej części kodu musimy go przypisać do jakiejś zmiennej. Czym są więc zmienne?
Nie da się ukryć, że chyba najważniejszymi strukturami w programowaniu są zmienne oraz ich specjalna odmiana – stałe. Jak sama nazwa wskazuje zmienne przechowują jakieś dane, którymi możemy operować w programie zmieniając je, dodając lub usuwając. Podobnie ma się ze stałymi, z tą różnicą, że ich zmieniać nie powinniśmy. Właśnie – nie powinniśmy, czy nie możemy? W wielu językach programowania zamiana wartości stałej wiąże się z wyskoczeniem błędu krytycznego, który przerywa działanie aplikacji. W Ruby jest inaczej, bo po takiej operacji interpreter nie zwróci błędu, ale tylko ostrzeżenie o próbie zmiany wartości będącej stałą.
Jak jednak korzystać z tych dobrodziejstw? Zmienne od stałych różnią się nazwą – zmienne zaczynamy zawsze od małej litery lub podkreślnika (_), natomiast stałe od dużej litery.

Ciekawostka...
W rzeczywistości zmienne oraz stałe to nic innego jak adres w pamięci komputera. Wyobraźcie sobie kość pamięci, która złożona jest z dużej ilości kostek. Każda kostka zawiera jakąś porcję danych. Wtedy zmienna bądź stała będzie tylko wskaźnikiem lub adresem (często też nazywanym referencją) danej kostki, dzięki któremu możemy łatwo odszukać daną wartości w całym zbiorze naszych kostek. Nam jednak wystarczy wiedzieć, że jest to pewnego rodzaju wskaźnik na dany element (tak jak np. nick na forum jest wskaźnikiem do Waszego profilu).


{} Listing 2.2 a = 2 b = 10 C = 13 #teraz pozmieniajmy trochę wartości a = 4 # teraz zmienna a ma wartość 4 b = 10 + 5 # zmienna b przyjęła wartość 15 C = 13 – a # ostrzeżenie! C jest stałą i nie powinna podlegać modyfikacji # mimo to trzeba uważać, bo teraz jej wartość to 13-a, czyli 9!
Pamiętać powinniśmy o jednej bardzo istotnej sprawie. Choć zmienne są referencjami (elementami wskazującymi obiekt w pamięci komputera) to bardzo często ich użycie w Ruby oznacza odwołanie się do wartości wskazywanej, a nie do adresu pamięci (innymi słowy - podczas przypisania pierwszej zmiennej do drugiej przepisywana jest jej wartość, a nie adres). Problem ten pokazuje listing 2.3.

{} Listing 2.3 a = 20 b = a + 5 # zmienna b przyjęła wartość 25 # po odwołaniu się do elementu wskazanego przez a a = 10 print (b) #=> 25 # choć moglibyśmy sądzić, że b teraz równe jest a + 5, czyli 15 (10+5) # to zmienna b wciąż ma wartość 25, mimo iż zmieniliśmy wartość a
Wróćmy zatem do naszego pytania z początku rozdziału – co zrobić, aby móc korzystać z dobrodziejstw naszej klasy bez ciągłego jej tworzenia? Trzeba przypisać ją oczywiście do zmiennej. Wtedy taka zmienna będzie wskazywać nasz stworzony obiekt, czyli będzie jego uchwytem.

{} Listing 2.4 class Czlowiek def initialize @waga = 70 @wzrost = 180 @wiek = 18 end def jedz end def rośnij end def oddychaj end end # kobieta zmienną jest ewa = Czlowiek.new

Zmienna zmiennej nie równa
Zrozumieliśmy zasadę działania zmiennych, ale to nie wszystko, co powinniśmy o nich wiedzieć. Kolejną istotną rzeczą jest typ zmiennej, czyli to jak jest ona prezentowana w kodzie i jak ma być interpretowana przez komputer. Przecież nie możemy wykonać sumowania 5 + „a”. Sam w Ruby zmienne dzielę na trzy kategorie – podstawowe, wbudowane oraz zewnętrzne.

Podstawowe zmienne
Zmienne kategorii podstawowej to te, które są w pewnym sensie wspomagane przez składnię języka. Zauważcie, że pisałem, iż każdy element w Ruby jest obiektem – liczba 8 i tekst „witaj” także. Jednak, aby je stworzyć nie musimy ich konstruować tak, jak innych obiektów, czyli poprzez „Fixnum.new(8)”, czy „String.new(„witaj”)”. Przyszedł więc czas, aby zaznajomić się z tymi podstawowymi zmiennymi, które można podzielić na kilka typów: liczby, znaki, wartości logiczne, tablice, wyrażenia regularne, a także klasy i moduły.
Jak w każdym języku programowania, tak i w Ruby zmienne posiadają operatory. Pierwszy z nich już, chcąc nie chcąc, poznaliśmy. Mowa o operatorze przypisania, który prezentowany pod symbolem znaku równości (=) przypisuje danej zmiennej wartość. Kolejne z nich będziemy poznawać razem z postępami w naszej nauce, jednak musicie na nie uważać, bo niektóre z nich wykonują różne czynności w zależności od typu zmiennych, jakich dotyczą.
Liczby
Istnieje kilka podtypów zmiennych liczbowych. Najpopularniejszą odmianą jest Fixnum (w innych językach często określana mianem Integer), czyli liczba całkowita. Może ona przyjmować tylko wartości z zakresu zależnego od maszyny, na której jest uruchomiona (z odjęciem jednego bitu), czyli zwykle jest to liczba 31 albo 63 bitowa. Jest to jednak bardziej ciekawostką, gdyż za każdym razem po przekroczeniu tej granicy liczba konwertowana jest automatycznie do innego typu zmiennych – Bignum. Dla naszych potrzeb możemy przyjąć, że jest on równoznaczny z typem Fixnum.
Trzecim podtypem jest Float, czyli liczba zmiennoprzecinkowa. Jaka to liczba? Tak, właśnie ta, która ma przecinek (ma część ułamkową).. =)
Kolejną ważną sprawą jaka tyczy się liczb to kolejność wykonywania na nich działań. Całe szczęście Ruby pozbawione jest tego typu pułapek matematycznych i operatory matematyczne zachowują swoje priorytety matematyczne (czyli kolejność wykonywania działań), a nie obiektowe (czyli od lewej do prawej). Jednak, aby nie oduczyć Was oraz siebie dobrych nawyków sam będę starał się odpowiednio stawiać nawiasy w tego typu wyrażeniach (poza poniższym przykładem).

{} Listing 2.5 liczba = 1 + 2 * 3 # 1 + (2 * 3) print liczba #=> 7 liczba = 2 * 3 + 1 # (2 * 3) + 1 print liczba #=> 7
Typowymi dla liczb operatorami są: operatory arytmetyczne ('+', '-', '*', '/', '**', '%'), operatory przypisania (wyglądają tak, jak arytmetyczne, ale są zakończone znakiem równości, np. '+=', '**=') i operatory porównania ('==', '!=', '<=', '>=', '<', '>'). Pamiętajcie też o tym, że wynikiem działań dwóch liczb całkowitych z operatorami arytmetycznymi lub przypisania zawsze zostanie liczba całkowita! Ten problem jest ukazany przy dzieleniu w Listingu 2.6.

Ciekawostka...
W wielu językach programowania występują także przydatne operatory inkrementacji (zwiększania wartości o 1) i dekrementacji (zmniejszania wartości o 1), które zapisuje się odpowiednio: 'i++' oraz 'i--'. W Ruby taka struktura nie występuje i trzeba się posługiwać kolejno 'i += 1' oraz 'i -= 1'.


{} Listing 2.6 # operatory arytmetyczne: a = 5 b = 2 print (a + b) # 5 + 2 <- sumowanie #=> 7 print (a – b) # 5 – 2 <- odejmowanie #=> 3 print (a * b) # 5 * 2 <- mnożenie #=> 10 print (a / b) # 5 / 2 <- dzielenie #=> 2 # dzielimy dwie liczby typu całkowitego, wiec wynik także jest # liczbą całkowitą, mimo że w rzeczywistości powinno być 2.5 print (a % b) # 5 % 2 <- reszta z dzielenia #=> 1 print (a ** b) # 5 ** 2 <- potęgowanie #=> 25 # operatory przypisania: a += b # równoznaczne z a = a + b a –= b # równoznaczne z a = a - b a *= b # równoznaczne z a = a * b a /= b # równoznaczne z a = a / b a %= b # równoznaczne z a = a % b a **= b # równoznaczne z a = a ** b # operatory porównania: a = 5 b = 2 print (a == b) # czy 5 jest równe 2? #=> false print (a != b) # czy 5 jest różne od 2? #=> true print (a <= b) # czy 5 jest mniejsze lub równe 2? #=> false print (a >= b) # czy 5 jest większe lub równe 2? #=> true print (a < b) # czy 5 jest mniejsze od 2? #=> false print (a > b) # czy 5 jest większe od 2? #=> true
Łańcuchy znaków
Choć mogą strasznie brzmieć w rzeczywistości łańcuchy znaków są zwykłym tekstem. Ciągi tekstu w programowaniu nazywa się stringami (od 'sznur', 'ciąg', a nie rodzaju bielizny zbereźniki =p) i zapisujemy je intuicyjnie wpisując w apostrofy lub cudzysłowy. Jeśli w tekście chcemy użyć dodatkowego znaku apostrofu lub cudzysłowu, poprzedzamy go backslashem.
Mimo że w dużej ilości przypadków nie ma znaczenia jakim sposobem zapiszemy ciąg znaków, tak naprawdę różnica jest spora. String napisany w apostrofach jest prezentowany dosłownie, bez formatowania, natomiast w cudzysłowach interpretuje wszelkie znaki specjalne, a nawet zezwala na dołączenie wartości zmiennej, która jest konwertowana do postaci znakowej.
{} Listing 2.7 # napis w apostrofach: napis = 'jakiś sobie \n \'łańcuch znaków\'' print napis #=> jakiś sobie \n 'łańcuch znaków' # napis w cudzysłowach: a = 5 napis = "\tjakiś sobie \n \"łańcuch znaków\", który zawiera liczbę #{a}" print napis #=> jakiś sobie #=> "łańcuch znaków", który zawiera liczbę 5
Jak widać na powyższym przykładzie - różnica może być znacząca. Jednak co oznaczają te poszczególne krzaczki? Znaki poprzedzone backslashem to tzw. znaki specjalne, szeroko używane w informatyce. Przykładowo literka t poprzedzona ukośnikiem (\t) oznacza użycie tabulatora, z kolei n (\n) wstawia znak łamania linii (czyli łopatologicznie mówiąc - Enter). Jeśli natomiast chcemy użyć w ciągu znaków jakiejś zmiennej wywołujemy ją w nawiasach klamrowych i poprzedzamy znakiem hash (#{...}), przy czym w klamrze tej możemy używać metod klasy.
{} Listing 2.8 # mamy zmienną liczbową a = -16 # dodajemy ją do tekstu wywołując metodę .abs, # która zwraca wartość bezwzględą liczby: napis = "Zmienna a ma wartość bezwzględą równą #{ a.abs }." print napis #=> Zmienna a ma wartość bezwzględą równą 16.
Ciekawostka...
W rzeczywistości ciąg znaków to tablica, której elementami są kolejne znaki w łańcuchu. Przykładowo tekst „kotek” to łańcuch znaków będący tablicą, której pierwszym elementem jest znak 'k', drugim 'o' itd. W języku C typ zmiennej przechowującej pojedynczy znak to char, jednak tak naprawdę nie przechowuje ona samego znaku ('k', 'o', 't' itd.), ale jego reprezentację liczbową.
Jeśli interesuje Cię ten temat zapoznaj się z najpopularniejszą tablicą kodów – ASCII. Innymi, popularnymi tablicami (które już pozwalają na używanie polskich znaków diakrytycznych) są tablice Unicode (dla nas istotne to Latin 2, czyli ISO-8859-2 oraz UTF8).


Stringi także posiadają swoje operatory, pozwalające w prosty sposób na nich działać. Poza operatorem przypisania mamy operatory konkatenacji (czyli łączenia łańcuchów) i porównania (niektóre zdeprecjonowane i nie zaleca się ich używania).
{} Listing 2.9 # dwa teksty tekst = "Ala ma kota" napis = ", a kot ma robota" # konkatenacja: wynik = tekst + napis print wynik #=> Ala ma kota, a kot ma robota wynik = tekst wynik << napis wynik.concat(33) #dodajemy na końcu znak o wartości liczbowej 33, czyli wykrzyknik print wynik #=> Ala ma kota, a kot ma robota! wynik = "Ha " * 3 print wynik #=> Ha Ha Ha
Poza operatorami klasa string posiada masę ciekawych dla nas metod, których użycie przedstawione jest na listingu 2.10. Warto jednak zwrócić uwagę na pewne konwencje zastosowane w języku - otóż przyjęło się w Ruby, że metody kończące się znakiem zapytania zwracają wartość logiczną, notomiast kończące się wykrzyknieniem nadpisują wartość zmiennej.
{} Listing 2.10 tekst = " Jestem tekstem !" print tekst.empty? # sprawdza, czy ciąg znaków jest pusty #=> false print tekst.sub("!","?") # dokonuje zamiany pierwszego wystąpienia znaku na inny #=> Jestem tekstem ? # jednak wywołanie tej metody z wykrzyknieniem zmienia nam także wartość # samej zmiennej.. # zmienna 'tekst' ma wartość ' Jestem tekstem !' tekst.sub!("!","?") # teraz natomiast zmienna 'tekst' ma przypisaną wartość ' Jestem tekstem ?' print tekst.chop! # ta metoda usuwa ostatni znak łańcucha #=> Jestem tekstem # w powyższym wywołaniu wciąż występuje spacja na końcu wiersza print tekst.strip! # usuwa wszystkie białe znaki z obu stron łańcucha #=> Jestem tekstem # w tym wywołaniu spacja z początku i końca wiersza znika # Inne użyteczne metody: print tekst.gsub("e","3") # zamienia wszystkie podane znaki na inne #=> J3st3m t3kst3m print tekst.delete! "st" # usuwa z łańcucha podane znaki #=> Jeem ekem print tekst.squeeze # ściska tekst, usuwając powtarzające się znaki #=> Jem ekem print tekst.upcase! # zamienia tekst na wersaliki #=> JEM EKEM print tekst.downcase! # zamienia tekst na małe litery #=> jem ekem print tekst.capitalize! # ustawia pierwszą literę dużą, a pozostałe małe #=> Jem ekem print tekst.reverse # odwraca tablicę łańcucha tyłem na przód #=> meke meJ # są jeszcze dwie funkcje zwracające rozmiar łańcucha: # tekst.length mówi o ilości zajmowanej pamięci, więc nie zawsze # jest dobrym rozwiązaniem do sprawdzania długości tekstu # tekst.size zwraca ilość znaków w tablicy łańcuchów (ilość liter, cyfer..)
Wartości logiczne
Pod ten rodzaj zmiennych podchodzą zarówno wartości logiczne (prawda, fałsz), jak i wartość pusta. Choć są to najprostsze typy danych, są także chyba najczęściej używane. Od zwykłego sprawdzania warunków (czy x > 5?), na prostej informacji o stanie klasy kończąc. W Ruby wartości logiczne przyjmują nazwy od ich angielskich odpowiedników, czyli 'true' i 'false', natomiast wartość pusta określana jest mianem 'nil'.

Ważne!
W języku Ruby wartości fałszu mają tylko i wyłącznie 'false' oraz 'nil'. Zatem puste tablice, liczba 0, czy pusty ciąg znaków traktowany jest jako logiczna prawda:

{} Listing 2.11 a = 0 b = [] c = "" d = nil # o instrukcjach warunkowych będziemy mówić później # ale jeśli uważnie prześledzisz i 'przetłumaczysz' kod # zrozumiesz jego działanie if a == true print "true" else print "false" end #=> true if b == true print "true" else print "false" end #=> true if c == true print "true" else print "false" end #=> true if d == true print "true" else print "false" end #=> false
Tablice
Tablice to pewnego rodzaju zgrupowania lub kontenery innych wartości. Występują w zasadzie w każdym języku programowania i spełniają bardzo istotną rolę. Jedną z opcji ich zastosowania mogliście podziwiać podczas omawiania zmiennych typu znakowego, czyli łańcuchów tekstu. W rzeczywistości każdy string jest tablicą, której poszczególne części są pojedynczymi znakami, jednak same tablice można zaprząc do innych, ciekawych rozwiązań. Elementy tablicy można definiować, dodawać, modyfikować oraz usuwać na różne sposoby:
{} Listing 2.12 # tablica z 4 elementami: tablica = [1,2,3,4] # tak naprawdę tablice mogą zawierać dowolne inne typy zmiennych: tablica = ["pierwszy", "drugi", "trzeci", "czwarty"] # ba! nic nie stoi na przeszkodzie, # aby elementem tablicy była inna tablica! tab1 = [1, 3, 10] tab2 = [3, 13, 2, 10, 10] tab3 = ["tekst"] tablica = [tab1, tab2, tab3, ["a","b"] ] # możemy także dodawać różne typy: tablica = [tab1, "drugi", 3] # w poniższy sposób możemy stworzyć sobie automatycznie # tablicę z np. pięcioma wartościami pustymi: tablica = Array.new(5)
No dobrze. Potrafimy tworzyć własne tablice danych. Wypadałoby jednak, abyśmy potrafili z nimi robić coś więcej, nieprawdaż? =) W celu wyłuskania elementu tablicy posłużyć się możemy operatorem indeksowania ([]), pamiętając że tablice w Ruby indeksowane są od numeru 0.
{} Listing 2.13 tablica = ["raz", "dwa", "trzy"] # wyświetlamy pierwszy element print tablica[0] #=> raz # wyświetlamy ostatni element print tablica[-1] #=> trzy # wyświetlamy 10-ty element print tablica[10] #=> nil # wyświetlamy elementy od drugiego do trzeciego print tablica[1..2] #=> dwa trzy # wyświetlamy całą tablicę print tablica #=> raz dwa trzy
Tablice mają całą masę swoich metod i operatorów, dlatego też będziemy je poznawać, gdy zajdzie taka potrzeba (o wszystkich możecie poszukać w dokumentacji Ruby) - tu natomiast przedstawię te dla nas na razie najistotniejsze:
{} Listing 2.14 tablica1 = [3, 5, 14] tablica2 = [1, 9, 10, 5] # sumujemy tablice tablica = tablica1 + tablica2 # tablica = [3, 5, 14, 1, 9, 10, 5] # odejmujemy tablice tablica = tablica1 - tablica2 # tablica = [3, 14] # część wspólna tablic tablica = tablica1 & tablica2 # tablica = [5] # dodatnie nowego elementu tablica1 << 0 tablica2.push 8 # tablica1 = [3, 5, 14, 0] # tablica2 = [1, 9, 10, 5, 8] # odejmowanie elementu z różnych stron tablica1.pop tablica2.shift # tablica1 = [3, 5, 14] # tablica2 = [9, 10, 5, 8]
Specyficznym rodzajem tablic są tzw. tablice asocjacyjne, w Ruby określane mianem Hash. Od normalnych tablic odróżniają się tym, że indeksy tablic nie są liczbami, a łańcuchami znaków. Hashe definiujemy podając elementy wg. schematu 'klucz => wartość'. O samych tablicach asocjacyjnych także powiemy sobie w dalszych częściach kursu.
{} Listing 2.15 asocjacyjna = { 'raz' => 1, 'dwa' => 2, "trzy" => 3 } print asocjacyjna['dwa'] #=> 2 asocjacyjna['cztery'] = 4 print asocjacyjna['cztery'] #=> 4 # sprawdzamy, czy tablica ma klucz 'trzy' print asocjacyjna.has_key?('trzy') #=> true # sprawdzamy, czy tablica posiada wartość 8 print asocjacyjna.has_value?(8) #=> false
Wyrażenia regularne
Wyrażenia regularne, czyli dane typu Regexp to ciąg znaków, którym możemy zastąpić dowolne konstrukcje ciągów znaków. =) Samą definicję przeczytacie na Wikipedii, nam jednak ten typ danych nie będzie przez jakiś czas potrzebny, dlatego na jakiś czas wystarczy Wam tylko wiedzieć, że istnieje.

Klasy i moduły
O zmiennych tego typu już (być może trochę nieświadomie) mówiliśmy omawiając zagadnienie obiektowości. Zatem i samą klasę Class oraz Module. Innymi słowy - tworząc nową klasę lub moduł korzystamy z tego typu danych. Choć wiedza ta czasem może być przydatna, tak naprawdę nie jest to wiedza, bez której nie bylibyście w stanie czegoś napisać.

Zmienne wbudowane
Typy wbudowane to zmienne, które nie są tak wspomagane przez semantykę języka jak podstawowe, a jednocześnie od razu są gotowe do użycia. Przykładami tego typu są zmienne typu Time (operowanie czasem), czy Math (podstawowe działania matematyczne jak logarytm, sinus, czy pierwiastkowanie).

Zmienne zewnętrzne
Zmienne zewnętrzne to te typy danych, które są implementowane.. zewnętrznie. Inaczej mówiąc - należą do nich zarówno stworzone przez nas typy (klasy), jak i te wczytywane z bibliotek.

Podsumowując:
- wyróżniamy programowanie strukturalne, proceduralne i obiektowe - klasy to tylko definicje elementów świata w danym programie - obiekty to fizyczne odzwierciedlenie klas - mogą posiadać własne własności, różniące jeden obiekt od innego, mimo że pochodzą od tej samej klasy - ważnym fragmentem programowania jest istnienie zmiennych oraz ich specjalnego rodzaju - stałych - zmienne można podzielić na: podstawowe, wbudowane i zewnętrzne

Ćwiczenia i zadania:
- przypomnij sobie jakimi słowami kluczowymi tworzymy klasy, metody, a także jak je kończymy - od jakich znaków zaczynami nazwy zmiennych, a od jakich nazwy stałych? - wymień wszystkie typy zmiennych wbudowanych oraz oswój się z ich możliwościami zaprezentowanymi w tej części kursu

Postscriptum
Kończymy kolejną część kursu. Mam nadzieję, że tym razem łatwiej było Wam zrozumieć to, co chciałem przekazać.. =) w następnej części zajmiemy się instrukcjami warunkowymi, sterującymi, zasięgiem zmiennych oraz przy odrobinie szczęścia napiszemy już coś konkretniejszego w samym RGSS.