Czytany Wpis

Absolutne podstawy Lua. Zmienne

W dzisiejszym wpisie poświęconym absolutnym podstawom Lua zajmiemy się zmiennymi

Absolutne podstawy Lua. Zmienne

Dzisiejszy wpis będzie prawdopodobnie najkrótszym zamieszczonych w ramach cyklu poświęconego absolutnym podstawom Lua. Szczerze powiedziawszy zagadnieniu zmiennych nie planowałem dedykować całego tekstu, ale dość oryginalne podejście twórców tego języka do tematu zmiennych sprawiło, że odstąpiłem od tego zamiaru i stąd osobny wpis.

Czym są zatem zmienne? W praktyce są to pewne nazwy, dzięki którym możemy wielokrotnie używać pewnych wartości w naszym kodzie. W przypadku prób rozjaśnienia z czym mamy do czynienia dość często można spotkać się określeniem, że jest to rodzaj pojemnika, do którego wkładamy pewne rzeczy, by móc w każdej chwili po te ostatnie sięgnąć. Od strony praktycznej, to dość dobra analogia. Natomiast bardziej precyzyjnie należałoby jednak powiedzieć czy też napisać, że zmiana wskazuje na miejsce w pamięci komputera, gdzie jest przechowywana jest jakaś - zazwyczaj  pojedyncza - wartość. Czyli pojemnikiem tak naprawdę jest tutaj pamięć komputera, a nie sama zmienna, która jedynie wskazuje na odpowiednie miejsce w pamięci komputera i dlatego czasem lepiej jest mówić, że zmienna wskazuje na pewną wartość niż faktycznie ją przechowuje. Oczywiście ktoś może powiedzieć, że to zbędne dzielenie włosa na czworo i faktycznie w naszym przypadku nie będzie to miało większego znaczenia. Tym niemniej warto wiedzieć, iż w pewnych językach programowania ten “nieistotny” szczegół ma duże znaczenie dla sposobu programowania, a brak zrozumienia tej subtelnej różnicy może powodować, że kod nie będzie działał zgodnie z naszymi oczekiwaniami.

Przechodząc jednak do rzeczy: tworzenie zmiennych jest w przypadku Lua dość proste i składa się z dwóch kroków, czyli wywołania deklaracji zmiennej oraz przypisania do niej konkretnej wartości. Deklaracja to tak naprawdę ustanowienie nazwy dla naszej zmiennej, którą następnie będziemy używać w naszym kodzie ilekroć będziemy chcieli wywołać jakąś wartość. W Lua deklaracja polega to na użyciu słowa kluczowego local.

Dobrze byłoby jeśli nazwa zmiennej jakoś odpowiadałaby wartości, którą następnie do niej przypiszemy, choć nie zawsze jest to potrzebne (pewnie wrócimy do tej kwestii przy omawianiu działania pętli). Staranność w tym zakresie ułatwia potem czytanie i zrozumienie kodu, zwłaszcza jeśli po jakimś czasie do niego wrócimy i możemy już niewiele pamiętać z tego, co wcześniej tak naprawdę zbudowaliśmy w danym skrypcie. Jednym ze sposobów poprawienia czytelności przy tworzeniu nazw zmiennych jest używania stylu określanego jako camelCase, tj. w przypadku zmiennych zbudowanych z dwóch słów, jedno z nich piszemy z dużej litery na początku. Uwzględniając całość z tego, co napisałem deklaracja zmiennej wyglądałaby tak:

local mojaZmienna

przy czym w miejsce “mojaZmienna” wstawiamy dowolny (no prawie dowolny - o czym za chwilę) ciąg znaków.

Kolejnym krokiem po zadeklarowaniu nazwy zmiennej powinno być przypisanie do niej jakiejś wartości. Całość sprowadza się do tego, że z lewej strony podajemy nazwę zmiennej i dalej dodajemy znak równości, po którym z prawej strony wpisujemy interesującą nas wartość. Czyli całość wyglądałaby mniej więcej tak:

local mojaZmienna

mojaZmienna = “Nudziarz”

Tym niemniej bardzo często deklaracja zmiennej oraz przypisanie do niej wartości odbywa się w jednym kroku, czyli całość wówczas wygląda w ten sposób:

local mojaZmienna = “Nudziarz”

W ramach ciekawostki wspomnę, że jak dobrze poszperać, to okazuje się, iż każda zmienna jest zawsze powiązana z jakąś wartością, nawet jeśli nie wskazaliśmy tego bezpośrednio. Dzieje się tak, ponieważ w przypadku Lua w momencie deklaracji zmiennej z automatu przypisywana jest do niej wartość nil (wspominałem o tym typie danych w poprzednim wpisie). Dopiero potem możemy tę domyślną wartość zamienić na taką, która nas interesuje, dokonując przypisania wprost. Żeby się o tym przekonać wystarczy uruchomić w naszej piaskownicy Lua następujący kod:

local a

print (a)

a = 2

print(a)

Zamykając już kwestię tworzenia zmiennych warto jeszcze wspomnieć o zasadach rządzących ustanawianiem nazw zmiennych. O ile wspomnianych wcześniej styl camelCase to rodzaj czegoś co nazywa się mianem dobrych praktyk, do których żadną miarą nie musimy się do tego stosować, to są pewne żelazne reguły, których ignorować nie można przy pisaniu kodu w Lua. Oto one:

  1. nazwa zmiennej może składać się z liter, cyfr oraz podkreśleń (chodzi o symblo “_”, czasami nazywany podłogą) i tylko z nich, tym samym nie możemy używać żadnych innych znaków specjalnych typu wykrzyknik czy dwukropek,
  2. należy też pamiętać, że nazwa może zaczynać się od litery lub podkreślenia, lecz nigdy od cyfry, choć później możemy się nimi posługiwać,
  3. wielkość użytych liter ma znaczenie: zmiana o nazwie “dom” nie jest tożsama ze zmienną o nazwie chociażby “Dom” czy “DOM”, choć w wymowie te trzy wyrazy się nie różnią,
  4. nazwa zmiennej nie może być identyczna jak którekolwiek słowo kluczowe: dzisiaj poznaliśmy jedno z nich, czyli local, w następnych wpisach poznanym kilka kolejnych, natomiast jeśli będziemy używać do tworzenia zmiennych odpowiednio złożonych nazw (zwłaszcza w języku polskim) nie musimy specjalnie się tym przejmować.

Już praktycznie na sam koniec tego wprowadzenia do zmiennych, należy się słów kilka wytłumaczenie, po co w ogóle te zmienne są potrzebne? Czyż nie lepiej i prościej posługiwać się wprost pewnymi wartościami? Czasami może tak być faktycznie, ale z drugiej strony pewnych zadań nie da się realizować bez tych elementów kodowania. Przecież nie zawsze wartość, której używamy w programie będzie pochodziła wyłącznie od nas, gdy chociażby nasza aplikacja oczekuje pewnych informacji z zewnątrz (np. od  użytkownika, który coś powinien wpisać na klawiaturze). Wówczas musimy tę wartość zapisać pod postacią jakiejś zmiennej właśnie. Co więcej pewnych ważnych konstrukcji programistycznych (np. pętli) nie da się realizować bez użycia zmiennych, a przynajmniej trudno mi sobie to wyobrazić. Naprawdę bez zmiennych nie da się zaprogramować czegoś bardziej złożonego niż na przykład proste wykonanie jakiś działań matematycznych, ale nawet wówczas użycie zmiennych może ułatwić nam życie.

Weźmy na warsztat proste ćwiczenie polegające na obliczaniu czasu, jaki potrzebny jest światłu czas na pokonanie drogi od Słońca do poszczególnych planet naszego układu słonecznego. Jak część z Was zapewne wie, światło w próżni porusza się ze stałą prędkością wynoszącą 299 792 458 metrów na sekundę, czyli “całkiem” szybko, ale mimo wszystko jest to pewne wartość skończona. Znamy też odległość poszczególnych planet od Słońca w konkretnej fazie ich podróży wokół centralnej gwiazdy. Jak uczą nas astronomowie już od kilku wieków, planety nie poruszają się wokół Słońca po okręgach, ale elipsach, więc ten dystans bywa zmienny. Na potrzeby naszego ćwiczenia weźmiemy ten moment (fachowo nazywany aphelium), kiedy światło będzie miało najdłuższą drogę do przebycie. Dla ziemi jest to około 152 milionów kilometrów. Mając takie dane wystarczyłoby napisać następującą instrukcję w Lua:

print(152000000/299792)

by w efekcie otrzymać informację, że w takiej sytuacji światło podróżuje około 507 sekund od Słońca do Ziemi.

Ale co jeśli chcielibyśmy obliczyć ten czas dla różnych faz podróży naszej planety wokół Słońca? Oczywiście musimy wypisać odpowiednią ilość równań, żmudnie wklepując te cyferki, bacząc czy przypadkiem się nie pomyliliśmy. Ale czy faktycznie musimy robić tak każdorazowo? W tym momencie z pomocą właśnie przychodzą zmienne, do których możemy przypisać odpowiednie wartości i odwoływać się do nich zawsze, gdy zajdzie taka potrzeba. Wówczas nasze ćwiczenie mogłoby wyglądać tak:

local a = 152000000 --odległość w kilometrach w aphelium (najawiększy dystans)

local p = 147100000 --odległość w kilometrach w peryhelium (najmniejszy dystans)

local sr = 149600000 --średnia odległość od Słońca

local predkoscSwiatla = 299792 --prędkość światła w kilometrach na sekundę‌

czasA = a/predkoscSwiatla

czasP = p/predkoscSwiatla

czasSr = sr/predkoscSwiatla‌

print (czasA)

print (czasP)

print(czasSr)

Jak widać na powyższym przykładzie, najpierw utworzyliśmy zmienne odpowiadające 3 różnym odległościom Ziemi od Słońca oraz zmienną odpowiadającą prędkości światła. W efekcie później już operowaliśmy zmiennymi, a nie wielkościami, którymi są do nich przypisane. Oczywiście w tak prostym przykładzie nie otrzymaliśmy jakiegoś wielkiego zysku z tego zabiegu, tym niemniej w przypadku napisania stosownej funkcji pożytek z takiego podejścia byłby bardziej widoczny. Jednakże o funkcjach będziemy się uczyli nieco później.

Przy okazji udało się przemycić kwestię komentarzy, czyli opisów w kodzie, które w żaden sposób nie wpływają na działanie programu (są pomijane przez interpreter). W Lua wywołuje się za pomocą podwójnych myślników, po których do końca linii możemy pisać już dowolne rzeczy. Umieszczanie komentarzy przy pisaniu aplikacji/skryptów to dobry zwyczaj, nawet w przypadku krótkich programów, ponieważ od razu mówią nam one, do czego służy dany fragment kodu. Tym niemniej nie należy przesadzać z ich ilością, czyli nie ma potrzeby komentowania wszystkiego, a zwłaszcza dość oczywistych elementów programu.

***
Kończąc już kwestię zmiennych dodam tylko, że przedstawiony wyżej sposób tworzenia zmiennych nie jest jedynym, jaki oferuje Lua. Otóż dopuszcza się w tym języku pominięcie słowa local, tym niemniej na potrzeby naszego kursu zapomnijmy o występowaniu takiej możliwości (z resztą takie właśnie podejście - używanie słowa kluczowego local -  zaprezentowane zostało przez twórców Robloxa w przygotowanym przez nich tutorialu). Wspominam o tym wyłącznie z tego powodu, iż widziałem w Internetach tutoriale do Robloxa, które prezentowały to drugie podejście (tj. bez użycia słowa kluczowego local). Podejrzewam, że w przypadku prostych skryptów tworzonych w Roblox Studio nie powinno to robić zasadniczej różnicy i generować rozlicznych problemów, ale dostrzegam tutaj pewne pułapki, które znają osoby programujące na ten przykład w Javascript, które używają słowa kluczowego var zamiast nowszego let. Wyjaśnienie tego zagadnienia wymagałoby jednak wprowadzenia do kwestii zasięgu zmiennych, co zdecydowanie wykracza poza zakres niniejszego wprowadzenia do ABSOLUTNYCH podstaw Lua.