A Lua programozási nyelv

Utasítások, vezérlési szerkezetek

A Lua blokkstruktúrált nyelv. A blokk nem más, mint utasítások sorozata. Az utasítások száma tetszőleges, üres utasítást a nyelv nem tartalmaz. Egy blokkot explicit módon kijelölhetünk:

do blokk end

Egy ilyen módon kijelölt blokk önálló utasításként működik. Az explicit blokk-kijelölés a változódeklarációk hatókörének megadására használható. A blokkok végrehajtási sorrendjét vezérlési szerkezetekkel befolyásolhatjuk. A blokkokat felépítő alapvető utasítások és a vezérlő szerkezetek a következőek:

Értékadás

A nyelv lehetőséget ad többszörös értékadásra. Formája a következő:

v1, v2, ..., vn = kif1, kif2, ..., kifm

A bal oldalon változók, a jobb oldalon pedig kifejezések vannak. A két oldalon az argumentumok száma különbözhet. Ilyenkor a következő szabályok érvényesek:

A többszörös értékadások szimultán módon hajtódnak végre. A következő kód például beállítja a[3] értékét 20-ra, anélkül, hogy megváltoztatná a[4] értékét:

i = 3 i, a[i] = i+1, 20

Ennek oka, hogy először az értékadás jobb oldala értékelődik ki, és csak ezután hajtjuk végre magát az értékadást. A következő utasítás tehát megcseréli az x és y változók értékét:

x, y = y, x

Szekvencia

Szekvenciák esetén nincs szükség explicit elválasztásra: két utasítást egy szóköz vagy egy újsor karakter is elválaszthat, de használható a más nyelvekben általában megszokott pontosvessző is erre a célra. Mivel üres utasítás nincs a Luában, ezért ezt nem tartalmazhat egy szekvencia.

Elágazás

A Luában csak kétirányú elágazásra van lehetőség, melynek formája a szokásos terminológiát követi:

if kifejezés then blokk else blokk end

Egymásba ágyazott elágazásoknál az else ág hovatartozásának kérdését az end utasítások alapján lehet eldönteni. Ugyancsak egymásba ágyazott elágazásoknál lehet hasznos, hogy nem kell kitenni a befejező end-et, hanem használható az elseif utasítás is:

if kifejezés then blokk elseif kifejezés then blokk ... else blokk end

Ezzel az utasítással a többirányú elágazásokhoz hasonló konstrukció hozható létre, ugyanis a nyelv case-utasítást nem tartalmaz, de vigyázat: ez szemantikailag csak egymásba ágyazott elágazásoknak felel meg!

Ciklus

Nem ismert lépésszámú ciklusok

Elöltesztelős ciklust a következő formában írhatunk:

while kifejezés do blokk end

A ciklus magja itt a kifejezés igaz értéke esetén fut le.

A hátultesztelős ciklus szintaxisa:

repeat blokk until kifejezés

A hátultesztelős ciklus a feltétel igaz értéke esetén áll le.

A repeat-until veszélyei

A repeat-until ciklus azonban a Luában igazából csak szintaktikus cukor, és illik vele vigyázni. Egészen addig az elvárásainknak megfelelően fut, amíg nem írunk mondjuk egy ilyen kódot:

x = 0 repeat local x = 1 ... until x == 0

A fenti ciklustól azt várnánk, hogy a ciklusmag egyszer fut le, majd mivel a globális x változó értéke 0, kilép. Ezzel szemben a futtatás eredménye egy végtelen ciklus lesz. Ennek oka az, hogy a ciklusfeltétel a ciklusmag hatókörében értékelődik ki, vagyis a ciklusunk igazából így fut:

x = 0 while true do local x = 1 ... if(x == 0) then break end end

Hátultesztelős ciklus használatakor így mindig figyelnünk kell, hogy ne fedjük el lokális deklarációkkal a ciklusfeltételben szereplő változókat, különben meglepő eredményeket kaphatunk.

Ismert lépésszámú ciklusok

Itt kétféle for ciklus áll rendelkezésünkre: numerikus és általános.

A numerikus for ciklus formája:

for változó = kif1, kif2, kif3 do blokk end

A változó értéke kif1 és kif2 határok között megy végig. A kif3 opcionális, ez adja meg a lépésközt. Alapértelmezett értéke 1. A kifejezések kiértékelése egyszer történik meg, a ciklusmag végrehajtása előtt. A változó automatikusan jön létre a ciklus kezdetekor és csak a cikluson belül látható, ott viszont értéke (sajnos) megváltoztatható. A ciklusváltozó értékének megváltoztatását a Lua tervezői sem ajánlják, a ciklus viselkedése ilyenkor nem definiált.

Luában a következő ekvivalens az előző ciklussal:

do local var, limit, step = tonumber(kif1), tonumber(kif2), tonumber(kif3) if not (var and limit and step) then error() end while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do local változó = var blokk var = var + step end end

Az általános for ciklus formája:

for változó in iterátor, fix, kezdő do blokk end

Itt az iterátor egy függvény, a fix és a kezdő tetszőleges kifejezés (akár el is hagyhatóak, ekkor a nil értéket használja helyettük a nyelv). Ez a ciklus a következőképpen működik. Az elején a változó felveszi a kezdő értékét. Ezután minden lépés előtt (tehát már az előbb leírt kezdő értékadás után is) a következő értékadás fut le:

változó = iterátor(fix, változó)

Ha az eredményként kapott érték nil, akkor véget ér a ciklus, különben lefut a blokk, és újra jön az iterátorhívás. A változó értékének megváltoztatása itt is definiálatlan viselkedést eredményez. Több változót is meg lehet adni a fejlécben. Ez akkor hasznos, ha az iterátor több eredményt ad vissza. Ilyenkor a további változók ezeket az értékeket kapják meg.

Iteráció táblákon for ciklussal

Egy tábla elemein való iterációra több standard függvényt is kínál a nyelv. A tábla egytől kezdődő egész számokkal hézag nélkül indexelt részén - tehát pl. 0,1,2,3,5 indexek esetén az 1,2,3 indexű elemeken - iterálhatunk végig az ipairs függvény segítségével:

for index, value in ipairs(table) do ... end

A tábla összes elemén való iterálásra használható ennek párja, a pairs függvény. Ez az összes kulcs-érték páron fut végig:

for key, value in pairs(table) do ... end

A pairs (és előtte az ipairs) függvény egy iterátor függvényt és magát a táblát adja vissza (ez utóbbi lesz a fix paraméter értéke). A ciklus így az csinálja, hogy a key és value változók sorban felveszik a tábla minden kulcs-érték párját, és minden érték mellett lefut egyszer a blokk. A bejárási sorrend nem determinisztikus.

Egyéb vezérlő utasítások

A ciklusokból való kilépésre használható a break utasítás, folytatásra azonban nincs lehetőség (nincs continue lehetőség a nyelvben). A break csak egy blokk utolsó utasításaként szerepelhet.

Függvényből való visszatérésre szolgál a return utasítás. A break-hez hasonlóan csak blokk utolsó utasítása lehet. A függvény visszatérési értékeit vesszővel elválasztva kell felsorolni az utasítás után, zárójelek nélkül.

Az 5.2-es Lua verzióban bevezették a feltétel nélküli vezérlésátadásra szolgáló goto utasítást. A vezérlés átadásához címkéket definiálhatunk, melyek a nyelv által szintén utasításokként vannak kezelve.
Egy címke az őt definiáló blokkon belül látható, kivéve, ha egy beágyazott blokkon belül egy ugyanolyan nevű másik címke elfedi. Ezen kívül beágyazott függvényeken belülről sem használhatjuk a külső blokkban definiált címkéket. A goto utasítás bármelyik látható címkére átadhatja a vezérlést, ha ezzel nem lép be egy lokális változó láthatósági körébe sem. (Azaz nem ugorhatjuk át a címke utáni kódban használt lokális változók inicializálását.)

for z=1,10 do for y=1,10 do for x=1,10 do if x^2 + y^2 == z^2 then print('found a Pythagorean triple:', x, y, z) print('now trying next z...') goto zcontinue end end end ::zcontinue:: end