LuaAan de slag met Lua


Opmerkingen

Lua-logo

Lua is minimalistische, lichtgewicht en insluitbare scripttaal. Het wordt ontworpen, geïmplementeerd en onderhouden door een team van PUC-Rio , de Pauselijke Katholieke Universiteit van Rio de Janeiro in Brazilië. De mailinglijst staat open om mee te doen.

Veelvoorkomende use-cases voor Lua omvatten scripting videogames, uitbreiding van applicaties met plug-ins en configs, inpakken van een aantal bedrijfslogica op hoog niveau of gewoon inbedden in apparaten zoals tv's, auto's, etc.

Voor taken met hoge prestaties is er onafhankelijke implementatie met behulp van just-in-time-compiler beschikbaar genaamd LuaJIT .

versies

Versie Notes Publicatiedatum
1.0 Eerste, niet-openbare release. 1993/07/28
1.1 Eerste publieke release. Conferentiedocument dat het beschrijft. 1994/07/08
2.1 Vanaf Lua 2.1 werd Lua vrij beschikbaar voor alle doeleinden, inclusief commercieel gebruik. Journal paper beschrijft het. 1995/02/07
2.2 Lange reeksen, de foutopsporingsinterface, betere stapel-tracebacks 1995/11/28
2.4 Externe luac compiler 1996/05/14
2.5 Patroonaanpassing en vararg-functies. 1996/11/19
3.0 Introductie van auxlib, een bibliotheek voor het schrijven van Lua-bibliotheken 1997/07/01
3.1 Anonieme functies en functiesluitingen via "waarden". 1998/07/11
3.2 Foutopsporingsbibliotheek en nieuwe tabelfuncties 1999/07/08
3.2.2 2000/02/22
4.0 Meerdere statussen, "voor" -instructies, API-vernieuwing. 2000/11/06
4.0.1 2002/07/04
5.0 Coroutines, metatables, volledige lexicale scoping, staartoproepen, booleans gaan naar MIT-licentie. 2003/04/11
5.0.3 2006-06-26
5.1 Vernieuwing van modulesysteem, incrementele afvalverzamelaar, metatabellen voor alle typen, luaconf.h-vernieuwing, volledig reentrant parser, variadische argumenten. 2006-02-21
5.1.5 2012-02-17
5.2 Noodafvalverzamelaar, ga naar, finalizers voor tafels. 2011-12-16
5.2.4 2015/03/07
5.3 Basis UTF-8 ondersteuning, bitgewijze ops, 32 / 64bit gehele getallen. 2015/01/12
5.3.4 Laatste versie. 2017/01/12

Comments

Opmerkingen over één regel in Lua beginnen met -- en gaan door tot het einde van de regel:

-- this is single line comment
-- need another line
-- huh?
 

Blok reacties beginnen met --[[ en eindigen met ]] :

--[[
    This is block comment.
    So, it can go on...
    and on...
    and on....
]]
 

Blokopmerkingen gebruiken dezelfde stijl van scheidingstekens als lange tekenreeksen; een willekeurig aantal gelijke tekens kan tussen de haakjes worden toegevoegd om een opmerking af te bakenen:

--[=[
    This is also a block comment
    We can include "]]" inside this comment
--]=]

--[==[
    This is also a block comment
    We can include "]=]" inside this comment
--]==]
 

Een handige truc om stukjes code te becommentariëren, is omringen met --[[ en --]] :

--[[
    print'Lua is lovely'
--]]
 

Om de chunk opnieuw te activeren, voeg je eenvoudig een - aan de volgorde van het openen van reacties:

---[[
    print'Lua is lovely'
--]]
 

Op deze manier start de volgorde -- in de eerste regel een opmerking van één regel, net als de laatste regel, en wordt er geen commentaar op de print instructie gegeven.

Als we nog een stap verder gaan, kunnen twee codeblokken zodanig worden ingesteld dat als het eerste blok wordt becommentarieerd, het tweede niet zal zijn, en omgekeerd:

---[[
  print 'Lua is love'
--[=[]]
  print 'Lua is life'
--]=]
 

Om de tweede chunk te activeren terwijl u de eerste chunk uitschakelt, verwijdert u de eerste - op de eerste regel:

--[[
  print 'Lua is love'
--[=[]]
  print 'Lua is life'
--]=]
 

Lua-programma's uitvoeren

Gewoonlijk wordt Lua verzonden met twee binaire bestanden:

  • lua - zelfstandige tolk en interactieve shell
  • luac - bytecode compiler

Laten we zeggen dat we een voorbeeldprogramma ( bottles_of_mate.lua ) als dit hebben:

local string = require "string"    

function bottle_take(bottles_available)

    local count_str = "%d bottles of mate on the wall."
    local take_str = "Take one down, pass it around, " .. count_str
    local end_str = "Oh noes, " .. count_str
    local buy_str = "Get some from the store, " .. count_str
    local bottles_left = 0

    if bottles_available > 0 then
         print(string.format(count_str, bottles_available))
         bottles_left = bottles_available - 1
         print(string.format(take_str, bottles_left))
    else
        print(string.format(end_str, bottles_available))
        bottles_left = 99
        print(string.format(buy_str, bottles_left))
    end

    return bottles_left
end

local bottle_count = 99

while true do
    bottle_count = bottle_take(bottle_count)
end
 

Het programma zelf kan worden uitgevoerd door het volgende uit te voeren op uw shell:

$ lua bottles_of_mate.lua
 

De uitvoer moet er zo uitzien, in de eindeloze lus:

Get some from the store, 99 bottles of mate on the wall.
99 bottles of mate on the wall.
Take one down, pass it around, 98 bottles of mate on the wall.
98 bottles of mate on the wall.
Take one down, pass it around, 97 bottles of mate on the wall.
97 bottles of mate on the wall.
...
...
3 bottles of mate on the wall.
Take one down, pass it around, 2 bottles of mate on the wall.
2 bottles of mate on the wall.
Take one down, pass it around, 1 bottles of mate on the wall.
1 bottles of mate on the wall.
Take one down, pass it around, 0 bottles of mate on the wall.
Oh noes, 0 bottles of mate on the wall.
Get some from the store, 99 bottles of mate on the wall.
99 bottles of mate on the wall.
Take one down, pass it around, 98 bottles of mate on the wall.
...
 

Je kunt het programma compileren in Lua's bytecode door het volgende uit te voeren op je shell:

$ luac bottles_of_mate.lua -o bottles_of_mate.luac
 

Ook is een bytecode-lijst beschikbaar door het volgende uit te voeren:

$ luac -l bottles_of_mate.lua


main <./bottles.lua:0,0> (13 instructions, 52 bytes at 0x101d530)
0+ params, 4 slots, 0 upvalues, 2 locals, 4 constants, 1 function
    1    [1]    GETGLOBAL    0 -1    ; require
    2    [1]    LOADK        1 -2    ; "string"
    3    [1]    CALL         0 2 2
    4    [22]    CLOSURE      1 0    ; 0x101d710
    5    [22]    MOVE         0 0
    6    [3]    SETGLOBAL    1 -3    ; bottle_take
    7    [24]    LOADK        1 -4    ; 99
    8    [27]    GETGLOBAL    2 -3    ; bottle_take
    9    [27]    MOVE         3 1
    10    [27]    CALL         2 2 2
    11    [27]    MOVE         1 2
    12    [27]    JMP          -5    ; to 8
    13    [28]    RETURN       0 1

function <./bottles.lua:3,22> (46 instructions, 184 bytes at 0x101d710)
1 param, 10 slots, 1 upvalue, 6 locals, 9 constants, 0 functions
    1    [5]    LOADK        1 -1    ; "%d bottles of mate on the wall."
    2    [6]    LOADK        2 -2    ; "Take one down, pass it around, "
    3    [6]    MOVE         3 1
    4    [6]    CONCAT       2 2 3
    5    [7]    LOADK        3 -3    ; "Oh noes, "
    6    [7]    MOVE         4 1
    7    [7]    CONCAT       3 3 4
    8    [8]    LOADK        4 -4    ; "Get some from the store, "
    9    [8]    MOVE         5 1
    10    [8]    CONCAT       4 4 5
    11    [9]    LOADK        5 -5    ; 0
    12    [11]    EQ           1 0 -5    ; - 0
    13    [11]    JMP          16    ; to 30
    14    [12]    GETGLOBAL    6 -6    ; print
    15    [12]    GETUPVAL     7 0    ; string
    16    [12]    GETTABLE     7 7 -7    ; "format"
    17    [12]    MOVE         8 1
    18    [12]    MOVE         9 0
    19    [12]    CALL         7 3 0
    20    [12]    CALL         6 0 1
    21    [13]    SUB          5 0 -8    ; - 1
    22    [14]    GETGLOBAL    6 -6    ; print
    23    [14]    GETUPVAL     7 0    ; string
    24    [14]    GETTABLE     7 7 -7    ; "format"
    25    [14]    MOVE         8 2
    26    [14]    MOVE         9 5
    27    [14]    CALL         7 3 0
    28    [14]    CALL         6 0 1
    29    [14]    JMP          15    ; to 45
    30    [16]    GETGLOBAL    6 -6    ; print
    31    [16]    GETUPVAL     7 0    ; string
    32    [16]    GETTABLE     7 7 -7    ; "format"
    33    [16]    MOVE         8 3
    34    [16]    MOVE         9 0
    35    [16]    CALL         7 3 0
    36    [16]    CALL         6 0 1
    37    [17]    LOADK        5 -9    ; 99
    38    [18]    GETGLOBAL    6 -6    ; print
    39    [18]    GETUPVAL     7 0    ; string
    40    [18]    GETTABLE     7 7 -7    ; "format"
    41    [18]    MOVE         8 4
    42    [18]    MOVE         9 5
    43    [18]    CALL         7 3 0
    44    [18]    CALL         6 0 1
    45    [21]    RETURN       5 2
    46    [22]    RETURN       0 1
 

Ermee beginnen

variabelen

var = 50 -- a global variable
print(var) --> 50
do
  local var = 100 -- a local variable
  print(var) --> 100
end
print(var) --> 50
-- The global var (50) still exists 
-- The local var (100) has gone out of scope and can't be accessed any longer.
 

types

num = 20 -- a number
num = 20.001 -- still a number
str = "zaldrizes buzdari iksos daor" -- a string
tab = {1, 2, 3} -- a table (these have their own category)
bool = true -- a boolean value
bool = false -- the only other boolean value
print(type(num)) --> 'number'
print(type(str)) --> 'string'
print(type(bool)) --> 'boolean'
type(type(num)) --> 'string'

-- Functions are a type too, and first-class values in Lua.
print(type(print)) --> prints 'function'
old_print = print
print = function (x) old_print "I'm ignoring the param you passed me!" end
old_print(type(print)) --> Still prints 'function' since it's still a function.
-- But we've (unhelpfully) redefined the behavior of print.
print("Hello, world!") --> prints "I'm ignoring the param you passed me!"
 

Het speciale type nil

Een ander type in Lua is nil . De enige waarde in het nil is nil . nil bestaat anders dan alle andere waarden in Lua. Het is een soort niet-waarde.

print(foo) -- This prints nil since there's nothing stored in the variable 'foo'.
foo = 20
print(foo) -- Now this prints 20 since we've assigned 'foo' a value of 20.

-- We can also use `nil` to undefine a variable
foo = nil -- Here we set 'foo' to nil so that it can be garbage-collected.

if nil then print "nil" end --> (prints nothing)
-- Only false and nil are considered false; every other value is true.
if 0 then print "0" end --> 0
if "" then print "Empty string!" --> Empty string!
 

uitdrukkingen

a = 3
b = a + 20 a = 2 print(b, a) -- hard to read, can also be written as
b = a + 20; a = 2; print(a, b) -- easier to read, ; are optional though
true and true --> returns true
true and 20 --> 20
false and 20 --> false
false or 20 --> 20
true or 20 --> true
tab or {}
  --> returns tab if it is defined
  --> returns {} if tab is undefined
  -- This is useful when we don't know if a variable exists
tab = tab or {} -- tab stays unchanged if it exists; tab becomes {} if it was previously nil.

a, b = 20, 30 -- this also works
a, b = b, a -- switches values
 

Functies definiëren

function name(parameter)
    return parameter
end
print(name(20)) --> 20
-- see function category for more information
name = function(parameter) return parameter end -- Same as above
 

booleans

Alleen false en nil evalueren als onwaar, al het andere, inclusief 0 en de lege string evalueren als waar.

garbage-collection

tab = {"lots", "of", "data"}
tab = nil; collectgarbage()
-- tab does no longer exist, and doesn't take up memory anymore.
 

tafels

tab1 = {"a", "b", "c"}
tab2 = tab1
tab2[1] = "d"
print(tab1[1]) --> 'd' -- table values only store references.
--> assigning tables does not copy its content, only the reference.

tab2 = nil; collectgarbage()
print(tab1) --> (prints table address) -- tab1 still exists; it didn't get garbage-collected.

tab1 = nil; collectgarbage()
-- No more references. Now it should actually be gone from memory.
 

Dit zijn de basisprincipes, maar er is een sectie over tabellen met meer informatie.

voorwaarden

if (condition) then
    -- do something
elseif (other_condition) then
    -- do something else
else
    -- do something
end
 

voor lussen

Er zijn twee soorten for lus in Lua: een numerieke for lus en een generieke for lus.

  • Een numeriek for lus heeft de volgende vorm:

    for a=1, 10, 2 do -- for a starting at 1, ending at 10, in steps of 2
      print(a) --> 1, 3, 5, 7, 9
    end
     

    De derde uitdrukking in een numeriek for lus is de stap waarmee de lus wordt opgehoogd. Dit maakt het gemakkelijk om reverse loops te doen:

     for a=10, 1, -1 do
       print(a) --> 10, 9, 8, 7, 6, etc.
     end
     

    Als de stapuitdrukking wordt weggelaten, gaat Lua uit van een standaardstap van 1.

     for a=1, 10 do
       print(a) --> 1, 2, 3, 4, 5, etc.
     end
     

    Merk ook op dat de lusvariabele lokaal is voor de for lus. Het zal niet bestaan nadat de lus voorbij is.

  • Algemeen for lussen werken door alle waarden die een iteratorfunctie retourneert:

    for key, value in pairs({"some", "table"}) do
      print(key, value)
      --> 1 some
      --> 2 table
    end
     

    Lua biedt verschillende ingebouwde iterators (bijv. pairs , ipairs ), en gebruikers kunnen ook hun eigen aangepaste iterators definiëren voor gebruik met generieke for loops.

blokken doen

local a = 10
do
    print(a) --> 10
    local a = 20
    print(a) --> 20
end
print(a) --> 10
 

Hallo Wereld

Dit is hallo wereldcode:

print("Hello World!")
 

Hoe het werkt? Het is makkelijk! Lua voert print() functie print() uit en gebruikt "Hello World" tekenreeks "Hello World" als argument.

Installatie

binaries

Lua binaries worden door de meeste GNU / Linux-distributies als een pakket aangeboden.

Op Debian, Ubuntu en hun derivaten kan het bijvoorbeeld worden verkregen door dit uit te voeren:

sudo apt-get install lua50
 
sudo apt-get install lua51
 
sudo apt-get install lua52
 

Er zijn enkele semi-officiële builds beschikbaar voor Windows, MacOS en enkele andere besturingssystemen die worden gehost bij SourceForge .

Apple-gebruikers kunnen Lua ook eenvoudig installeren met Homebrew :

brew install lua
 

(Momenteel heeft Homebrew 5.2.4, zie 5.3 voor Homebrew / versies .)

Bron

Bron is beschikbaar op de officiële pagina . Acquisitie van bronnen en zelf bouwen moet triviaal zijn. Op Linux-systemen moet het volgende voldoende zijn:

$ wget http://lua.org/ftp/lua-5.3.3.tar.gz
$ echo "a0341bc3d1415b814cc738b2ec01ae56045d64ef ./lua-5.3.3.tar.gz" | sha1sum -c -
$ tar -xvf ./lua-5.3.3.tar.gz
$ make -C ./lua-5.3.3/ linux
 

In het bovenstaande voorbeeld downloaden we in feite een bron- tarball van de officiële site, verifiëren we de controlesom en extraheren en voeren we het make . (Controleer de controlesom op de officiële pagina .)

Opmerking: u moet opgeven welk builddoel u wilt. In het voorbeeld hebben we linux gespecificeerd. Andere beschikbare macosx zijn solaris , aix , bsd , freebsd , macosx , mingw , etc. Bekijk doc/readme.html , dat is opgenomen in de bron, voor meer informatie. (U kunt ook de nieuwste versie van de README online vinden .)

modules

Standaardbibliotheken zijn beperkt tot primitieven:

  • coroutine - coroutinebeheerfunctionaliteit
  • debug - debug hooks and tools
  • io - basis IO-primitieven
  • package - modulebeheerfunctionaliteit
  • string - string en Lua-specifieke functionaliteit voor patroonovereenkomst
  • table - primitieven voor het omgaan met een essentieel maar complex Lua type - tabellen
  • os - basis OS-bewerkingen
  • utf8 - basis UTF-8 primitieven (sinds Lua 5.3)

Al die bibliotheken kunnen voor een specifieke build worden uitgeschakeld of tijdens uitvoering worden geladen.

Lua-bibliotheken van derden en infrastructuur voor het distribueren van modules is schaars, maar verbetert. Projecten zoals LuaRocks , Lua Toolbox en LuaDist verbeteren de situatie. Veel informatie en veel suggesties zijn te vinden op de oudere Lua Wiki , maar houd er rekening mee dat sommige van deze informatie vrij oud en verouderd is.

Enkele lastige dingen

Soms gedraagt Lua zich niet zoals men zou denken na het lezen van de documentatie. Sommige van deze gevallen zijn:

Nul en niets zijn niet hetzelfde (COMMON PITFALL!)

Zoals verwacht, table.insert(my_table, 20) de waarde 20 aan de tabel, en table.insert(my_table, 5, 20) voegt de waarde 20 toe op de 5e positie. Wat doet table.insert(my_table, 5, nil) echter? Je zou verwachten dat het nil als helemaal geen argument behandelt en de waarde 5 aan het einde van de tabel invoegt, maar het voegt eigenlijk de waarde nil op de 5e positie van de tabel. Wanneer is dit een probleem?

(function(tab, value, position)
    table.insert(tab, position or value, position and value)
end)({}, 20)
-- This ends up calling table.insert({}, 20, nil)
-- and this doesn't do what it should (insert 20 at the end)
 

Hetzelfde gebeurt met tostring() :

print (tostring(nil)) -- this prints "nil"
table.insert({}, 20) -- this returns nothing
-- (not nil, but actually nothing (yes, I know, in lua those two SHOULD
-- be the same thing, but they aren't))

-- wrong:
print (tostring( table.insert({}, 20) ))
-- throws error because nothing ~= nil

--right:
local _tmp = table.insert({}, 20) -- after this _tmp contains nil
print(tostring(_tmp)) -- prints "nil" because suddenly nothing == nil
 

Dit kan ook leiden tot fouten bij het gebruik van code van derden. Als, bijvoorbeeld, de documentatie van een functie staten "returns donuts als je geluk hebt, niets anders", de uitvoering macht ziet er ongeveer als volgt

function func(lucky)
    if lucky then
        return "donuts"
    end
end
 

deze implementatie lijkt in eerste instantie redelijk; het retourneert donuts wanneer het moet, en wanneer u result = func(false) resultaat zal de waarde nil bevatten.

Als iemand echter print(tostring(func(false))) zou schrijven print(tostring(func(false))) zou lua een foutmelding geven die er ongeveer zo uitziet als deze stdin:1: bad argument #1 to 'tostring' (value expected)

Waarom is dat? tostring krijgt duidelijk een argument, ook al is het nil . Mis. func retourneert helemaal niets, dus tostring(func(false)) is hetzelfde als tostring() en NIET hetzelfde als tostring(nil) .

Fouten die zeggen "waarde verwacht" zijn een sterke indicatie dat dit de oorzaak van het probleem kan zijn.

Gaten achterlaten in arrays

Dit is een enorme valkuil als je nieuw bent bij lua, en er is veel informatie in de tabellencategorie