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.