A Lua (programozási nyelv) jelentősége a mai társadalomban tagadhatatlan. Legyen szó aktuális témáról, kiemelkedő személyiségről, kulturális jelenségről vagy alapvető fogalomról, a Lua (programozási nyelv) döntő szerepet játszik mindennapi életünkben. Ebben a cikkben a Lua (programozási nyelv)-hez kapcsolódó különböző szempontokat vizsgáljuk meg, a személyes szintre gyakorolt hatásától a globális szférára gyakorolt hatásáig. Részletes elemzéssel igyekszünk megérteni a Lua (programozási nyelv) relevanciáját és jelentőségét napjainkban, valamint időbeli alakulását. Hasonlóképpen megvizsgáljuk a különböző összefüggésekben betöltött szerepét és a társadalom más elemeivel való interakcióját. Ezzel az utazással reméljük, hogy rávilágítunk a Lua (programozási nyelv) fontosságára és összetettségére a mai társadalomban.
Lua | |
![]() | |
Paradigma | Imperatív |
Jellemző kiterjesztés |
|
Megjelent | 1993 |
Tervező | Roberto Ierusalimschy Waldemar Celes Luiz Henrique de Figueiredo |
Fejlesztő | Roberto Ierusalimschy |
Utolsó kiadás | 5.4.7 (stabil verzió, 2024. június 25.)[1] |
Dialektusok | Metalua, Idle, GSL Shell |
Megvalósítások | Lua, LuaJIT, LLVM-Lua, Lua Alchemy |
Hatással volt rá | C++, CLU, Modula, Scheme, SNOBOL |
Befolyásolt nyelvek | Io, GameMonkey, Squirrel, Falcon, MiniD |
Operációs rendszer | többplatformos |
Licenc | MIT-licenc |
Weboldal |
A Lua (portugálul: hold) egy nyílt forráskódú, beágyazható szkriptnyelv, amelyet 1993-ban fejlesztettek ki a brazíliai Katolikus Teológiai Egyetemen. Készítői fontosnak tartották az együttműködést a C nyelvű programokkal, programkönyvtárakkal. Platformfüggetlen; a programok futás előtt bájtkódra fordulnak. Bár önállóan is használható, de inkább beágyazott nyelvként tartják számon, ahogy a Tcl nyelvet is. Más script nyelvekhez képest nagy sebessége, bővíthetősége és 120 kB-os mérete népszerűvé tette a fejlesztők között.
Az értelmező egy C könyvtárból érhető el, ami API-ként szolgál, ha C programból hívják. Ez lehetővé teszi a két nyelv kevert használatát: a Lua is hívhat C függvényeket, és fordítva, a C is meghívhat Lua függvényeket.
ANSI C-ben készült, és az imperatív és a funkcionális paradigmákat támogatja; az objektumorientáltsághoz nem nyújt nyelvi eszközöket, mégis lehet objektumokat készíteni a tábla adattípus felhasználásával.
Az azonosítók betűkből, számokból, aláhúzásjelekből építkezhetnek, ahol az első jel nem lehet szám. A betűkészlet a helyi beállításoktól függ. Egy jel betű volta ellenőrizhető az isalpha
, szám volta az isalnum
függvénnyel.
A számok tartalmazhatnak törtrészt és decimális exponenst. A tizenhatos számrendszert a 0x
előtag jelzi, ahol az x lehet kis- vagy nagybetűs is.
A Lua forráskódban a kis- és nagybetűk nem minősülnek azonosnak.
A Lua beépített típusai:
Egy nil típusú változónak egyetlen lehetséges értéke van, a nil
. Ez a globális változók alapértelmezett értéke; a változók törölhetők is úgy, hogy értéküket nil
-re állítjuk.
Egy logikai változónak két lehetséges értéke van: true
és false
. Fontos hibaforrás, hogy a Rubyhoz hasonlóan csak a nil
és a false
hamis, az üres string vagy a nulla nem. A logikai műveletek: and
, or
, not
.
A számok alapértelmezetten dupla pontosságú lebegőpontos számok. Nincs külön egész típus. A számokon végezhető műveletek operátorai: +
, -
, *
, /
, és a hatványozás jele, a ^
. Az összehasonlításra a ==
, ~=
(nem egyenlő), <
, >
, <=
, >=
operátorok szolgálnak.
A függvények tárolhatók változókban, és átadhatók paraméterként. A C-ben írt programkönyvtárak felhasználásának elősegítésére a C függvények is kezelhetők így. Függvényhíváskor akkor is ki kell tenni a zárójelet, ha nem adunk meg paramétereket. A Javaban megszokott this
itt self
. Metódusok hívásakor az objektumot is fel kellene sorolni a paraméterek között:
objektum.metódus(objektum, paraméterek)
de létezik egy szintaktikus cukor ennek a lerövidítésére:
objektum:metódus(paraméterek)
A thread a többszálú programozás programszálainak típusa.
A rövid stringek megadhatók egyszeres vagy kétszeres idézőjelek között. Hosszabb stringek megadhatók hosszú szöveg
> formában is. A hosszú stringekben levő utasítások, escape sorozatok nem hajtódnak végre. Minden fajta string tárolhat tetszőleges Unicode karaktereket, amik a C fordító char
típusára képeződnek le. A fájlokat azonban mindig binárisan érdemes kezelni, mivel a nyelv az stdio
C könyvtárat használja, ami azonban nem garantálja a különféle kódolások megfelelő kezelését.
Az escape sorozatok ugyanazok, mint C-ben.
A userdata C-ben megvalósított adattípusokat tárol. Módosítani, rajta műveleteket végrehajtani csak C függvényekkel lehet, a Lua csak értékadást és egyenlőségvizsgálatot biztosít hozzá.
A table a Lua egyetlen összetett típusa, asszociatív tömb. A kulcsok lehetnek számok (ajánlottan csak egészek), stringek, másik táblák vagy függvények. A táblák automatikus indexelése a modernebb nyelvekhez hasonlóan 1-től kezdődik, mivel a 0 index hiánya nem igényel kihasználatlan helyfoglalást.
Bejárásuk kétféle módon lehetséges: csak az egész típusú kulcsokat (és a hozzájuk tartozó értékeket) nézzük végig 1-től az első nem létező kulcsig (ipairs
) vagy az összes kulcs-érték párt (pairs
).
Táblák létrehozhatók így:
x = {3.14, "ez egy string"}
Ilyenkor az egyes értékeket sorban az 1, 2, 3, ... kulcsokhoz rendeli.
String kulcsokat így lehet használni:
x =
{
nev = "Kovács János",
kor = 46,
fizetes = {ertek = 10000, penznem = "Ft"}
}
A táblák referencia szerint adódnak át:
a_table = {x = 10} -- Új tábla, egy kulcs-érték pár: "x" kulcs a 10-es számhoz.
print(a_table) -- A string kulcshoz tartozó érték kiíratása; itt 10.
b_table = a_table
b_table = 20 -- Az "x"-hez tartozó érték megváltoztatása 20-ra.
print(b_table) -- Az új érték kiíratása: 20.
print(a_table) -- ez is 20-at ír, mert az a_table és a b_table ugyanarra a táblára hivatkozik.
Kulcsok, értékek beszúrása, eltávolítása:
myTable = {"a", "b"}
table.insert(myTable, "c")
print(unpack(myTable)) -- eredménye: a b c
table.remove(myTable, 2)
print(unpack(myTable)) -- eredménye: a c
Egysoros megjegyzés:
-- Megjegyzés
Többsoros megjegyzés:
--[[Ide egy
többsoros
megjegyzés
került]]
A változók nevükkel hivatkozhatók.
A táblában levő értékek hivatkozhatók a tömböknél megszokott módon, pl. a
. Ha a kulcs string, akkor használható az a
és a.nev
alak is.
A változók láthatóság szempontjából háromfélék lehetnek: globális, lokális, és táblamezők. A változók deklarációjuktól kezdve egészen a legkisebb befoglaló blokk végéig láthatók. Egy változó lokálissá tehető, ha local
kulcsszóval deklaráljuk. A függvények paraméterei is lokálisnak tekinthetők. Minden más változó globális. A deklarált, de értéket még nem kapott változók értéke nil
. A függvények látják hívási helyük lokális változóit.
A Lua csak a kétirányú elágazást ismeri, a többágú elágazás valójában csak szintaktikus cukor:
if kifejezes then
blokk
else
blokk
end
if kifejezes then
blokk
elseif kifejezes then
blokk
elseif kifejezes then
blokk
...
else
blokk
end
Addig hajtja végre a ciklusmagot, amíg a feltétel igaz.
while feltétel do
-- Utasítások
end
repeat
-- Utasítások
until feltétel
A ciklusmagot egyszer mindenképpen végrehajtja, majd utána addig hajtja végre a ciklust, amíg a feltétel hamis (igazzá nem válik). Az until ciklus valójában csak szintaktikus cukor, nem hoz létre új láthatósági tartományt.
for index = start, finish, delta do
-- Utasítások
end
Az index
ciklusváltozót kezdetben start
-ra állítja, majd minden iteráció után delta
lépésközzel megnöveli. Addig fut, amíg a ciklusváltozó kisebb vagy egyenlő, mint a finish
.
Ha delta
= 1, akkor a lépésköz elhagyható:
for index = start, finish do
-- Utasítások
end
A Luában kétféle iteráló ciklus van. Az ipairs
1-től kezdve a kapott tábla összes egész szám kulcsán sorban végigiterál, egészen addig, amíg nil
értéket nem kap. A konvenció szerint ha egy változót kell valahol használni, aminek az értékét soha nem olvassuk (ez esetben a kulcs helyén), akkor az _
nevet adjuk neki.
for _, value in ipairs(lista) do
-- Utasítások
end
A pairs
a kapott tábla összes kulcs-érték párján végigiterál, függetlenül a kulcsok típusától.
for key, value in pairs(lista) do
-- Utasítások
end
A Luában a függvények átadhatók paraméterként, sőt, visszatérési értékek is lehetnek, ahogy a következő példa mutatja:
do
local oldprint = print -- a jelenlegi print függvény eltárolása oldprint néven
function print(s) -- a print függvény újradefiniálása, itt lehet a szokásos print függvényt használni
if s == "foo" then
oldprint("bar")
else
oldprint(s)
end
end
end
A régi print függvény csak az új print függvényen keresztül érhető el.
A Lua a lezártakat is támogatja:
function hozzaad (x)
-- visszatér egy új funkcióval, ami hozzáadja x-et a paraméterhez
return function(y)
--[[Amikor az x változóra hivatkozunk, ami kívül van az aktuális láthatósági tartományon
és az élettartama hosszabb, mint ennek a névtelen függvénynek,
akkor a Lua egy lezártat (closure) hoz létre]]
return x + y
end
end
negyplusz = hozzaad(4)
print(negyplusz(3)) --> kiirja a 7-et
Valahányszor meghívódik a hozzaad
, annyiszor új lezárt jön létre az x
változóhoz. Így a névtelen függvény mindig hozzáfér a paraméteréhez. A lezártat, mint minden más objektumot, a szemétszedő gyűjti be.
A metatáblák új lehetőségeket nyújtanak a táblák felhasználására. A következő példa egy végtelen táblát mutat be. Minden n-re fibs
az n-edik Fibonacci-számot adja a dinamikus programozás és a memorizálás segítségével:
fibs = { 1, 1 } -- fibs fibs kezdőértékei.
setmetatable(fibs, {
__index = function(name, n) -- Ezt hívja, ha még nincs fibs.
name = name + name -- Kiszámolja és megjegyzi fibs-et.
return name
end
})
Egy másik példa: a __call metametódus az objektumorientáltság érzetét adja:
newPerson = {} -- Új tábla 'newPerson' néven.
setmetatable(newPerson, {
__call = function(table,name,age) -- A newPerson táblát functable-lé teszi.
local person = {Name = name, Age = age} -- Lokális változó a később létrehozandó person attributumaival
return person -- A person tábla visszaadása, a person tábla változóinak beállítása
end
})
Bill = newPerson("Bill Raizer", 21) -- Új Person-t hoz létre
print(Bill.Name, Bill.Age) -- A name és az age attributumok kiíratása.
Bár a Luában nincs adatszerkezet rekordok létrehozására, mint például C-ben a struct
, a táblák erre a célra is használhatók. Ezt a használatot a nyelv szintaktikusan támogatja:
pont = { x = 10, y = 20 } -- Új tábla
print(pont) -- Az "x" koordináta kiíratása, itt 10
print(pont.x) -- Ugyanaz, mint az előző sorban, csak másként.
A táblák összetartozó függvényeket is tárolhatnak, ezzel átvehetik a névterek szerepét, objektumorientáltság érzetét adva:
Point = {} -- Új névtér létrehozása
Point.new = function (x, y) -- Konstruktor
return {x = x, y = y}
end
Point.set_x = function (self, x)
self.x = x
end
Point.get_x = function (self)
return self.x
end
A Lua táblák tömbökként is használhatók:
array = { "a", "b", "c", "d" } -- Az indexek automatikusan számozódnak.
print(array) -- A "b"-t írja ki. A Lua 1-től kezdi a tömbelemek indexelését.
print(#array) -- 4, a tábla hossza. A # operátor adja meg a táblák és a stringek hosszát.
array = "z" -- A 0 index használata.
print(#array) -- Most is 4, a nulladik index nem számítódik bele a hosszba.
Objektumok tömbjeként:
function newPoint(x, y) -- A "Point" objektum konstruktora
return { x = x, y = y } -- Új objektum létrehozása és visszaadása
end
array = { newPoint(10, 20), newPoint(30, 40), newPoint(50, 60) } -- Pontok tömbje
print(array.y) -- 40-et ír ki
A Lua táblák tömbrésszel és assziociatív tömbrésszel vannak implementálva. Korábban az egészet asszociatív tömbbel valósították meg, de ez az ábrázolás gyorsabb.[2]
A Lua lehetővé teszi új modulok létrehozását. A modulok kezelésére rendelkezésre áll a Luarocks modulkezelő.
Néhány modul a leggyakoribbak közül:
Modul | Leírás |
---|---|
LuaFileSystem | Hozzáférés a könyvtárszerkezethez és a fájlok jogaihoz |
LuaDoc | Dokumentációs eszköz a Lua-kódhoz. |
LuaSocket | Lua interfész a hálózati protokollokhoz: HTTP, FTP, SMTP, MIME, URL és LTN12. |
LuaSQL | Lua interfész a következőkhöz: PostgreSQL, ODBC, MySQL, SQLite, Oracle és az OLE DB. |
stdlib | Gyakori feladatok programkönyvtára a listákhoz, táblákhoz, a funkcionális és az objektumorientált programozáshoz, meg a reguláris kifejezésekhez. |
MD5 | Egyszerű kriptográfia |
Copas | Párhuzamosság támogatása, a korutinok képességeinek bővítése |
LuaZip | A .zip fájlok kezeléséhez. |
LuaInterface | Kapcsolatot teremt a Lua és a Microsoft .NET Common Language Runtime (CLR) között. |
LuaBitOps | C nyelvű kiterjesztés a számokon végzett bitenkénti műveletekhez. |
LuaXML | Az XML és a Lua társítása. |
Lanes | Több Lua környezet párhuzamos futtatása |
Penlight | Táblák, tömbök, stringek, fájlok, könyvtárak, adatok és funkcionális eszközök kezelelésének egyszerűsítése. |
Oil | Egyszerű és hatékony Object Request Broker (CORBA). |
A klasszikus Hello World! program Lua nyelven:
print("Hello World!")
A virtuális gép nem közvetlenül a Lua szkriptet hajtja végre, hanem futás közben bájtkódra fordítja, és ez fut. A szkriptek futtatás nélkül is fordíthatók. Maga a fordítás átlátható.
A Lua virtuális gép regiszteres, ezért a legtöbb virtuális gépnél jobban hasonlít a hardver felépítéséhez. Ez csökkenti az értékek átmásolásának és a függvényenkénti utasítások számát. A Lua 5 az egyik legrégibb regiszteres virtuális gép.[3] Az Android Dalvikja és a több nyelvre, köztük Perlre tervezett Parrot is ilyen.
Így fordítja a luac 5.1 virtuális gép a faktoriális függvényt:[4]
function <factorial.lua:1,6> (10 instructions, 40 bytes at 003D5818) 1 param, 3 slots, 0 upvalues, 1 local, 3 constants, 0 functions 1 EQ 0 0 -1 ; – 0 2 JMP 2 ; to 5 3 LOADK 1 -2 ; 1 4 RETURN 1 2 5 GETGLOBAL 1 -3 ; factorial 6 SUB 2 0 -2 ; – 1 7 CALL 1 2 2 8 MUL 1 0 1 9 RETURN 1 2 10 RETURN 0 1
A Luát alkalmazásokba ágyazott nyelvnek fejlesztették, ezért könnyen használható, robusztus C API-val látták el. Az API két részből áll: ezek a Lua core és a Lua auxiliary library.[5] Kiküszöböli a C kézi hivatkozáskezelését. Az API a nyelvhez hasonlóan minimalisztikus; a funkcionalitás bővítéséért az auxiliary library felelős, ami preprocesszor makrókkal egyszerűsíti a táblakezelést.
A Lua C API verem alapú. A veremműveleteket Lua függvények valósítják meg, továbbá léteznek táblakezelő függvények is, amik a veremből is hívhatók. Ez a verem indexelhető is. A Python tömbökhöz hasonlóan negatív indexek is használhatók; ezek a verem tetejétől (-1 a legfelső elem), a pozitív indexek a verem aljától számítódnak.
A C és a Lua közötti kommunikációt szintén a verem valósítja meg. A Lua függvénynek átadott argumentumok a verembe kerülnek, és az aktuális függvény lua_call
utasítással hívható. Ha C függvényt hívunk Luából, akkor az a verem tetejéről veszi a paramétereket.
Lua függvény hívása C-ből:
#include <stdio.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main()
{
lua_State *L = luaL_newstate();
if (luaL_dostring(L, "function foo (x,y) return x+y end")) exit(1);
lua_getglobal(L, "foo");
lua_pushinteger(L, 5);
lua_pushinteger(L, 3);
lua_call(L, 2, 1);
printf("Result: %d\n", lua_tointeger(L, -1));
return 0;
}
Fordítás és futtatás:
$ gcc -o hello -llua hello.c $ ./hello Result: 8
A C API speciális táblákat is elérhetővé tesz, amik pszeudoindexekkel hivatkozhatók a Lua veremből. A LUA_GLOBALSINDEX
tárolja a globális változókat, _G
a fő névtér. A LUA_REGISTRYINDEX
-ben tárolják a C függvények a Lua értékeket későbbi felhasználásra.
Kiterjesztő modulok is készíthetők a Lua API használatával. Ezek a könyvtárak kiterjesztik az értelmező funkcionalitását. A Lua szempontjából ezek névterek, vagyis táblák a maguk változóival és függvényeivel. Ezek a modulok a require
kulcsszóval tölthetők be.[5]
A LuaRocks csomagkezelő rendszerből egyre több modul érhető el,[6] a CPANhoz, a RubyGemshez és a Python Eggshez hasonlóan. További források a LuaForge és a lua-users.org wiki Lua Addonsa.[7]
Vannak csomagok a grafikus felülethez, a Perl/POSIX szabályos kifejezésekhez, a titkosításhoz, a fájltömörítéshez és még sok máshoz. A legtöbb népszerű nyelvhez vannak Lua kötések, például más szkript nyelvekhez.[8] A C++ megközelítés sablon alapú, és automatikus generátorokat használ.
Manapság a videójátékok nagy része rendelkezik Lua scriptelési lehetőséggel, ezen kívüli alkalmazások: