Débuter avec Lua

Commentaires

Les commentaires sur une seule ligne en Lua commencent par -- et continuent jusqu’à la fin de la ligne :

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

Les commentaires de bloc commencent par --[[ et se terminent par ]] :

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

Les commentaires de bloc utilisent le même style de délimiteurs que les chaînes longues ; n’importe quel nombre de signes égal peut être ajouté entre les parenthèses pour délimiter un commentaire :

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

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

Une astuce pour commenter des morceaux de code consiste à l’entourer de --[[ et --]] :

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

Pour réactiver le bloc, ajoutez simplement un “-” à la séquence d’ouverture du commentaire :

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

De cette façon, la séquence -- dans la première ligne commence un commentaire sur une seule ligne, tout comme la dernière ligne, et l’instruction print n’est pas commentée.

Pour aller plus loin, deux blocs de code peuvent être configurés de telle sorte que si le premier bloc est commenté, le second ne le sera pas, et vice versa :

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

Pour activer le deuxième bloc tout en désactivant le premier bloc, supprimez le “-” de début sur la première ligne :

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

Installation

Binaires

Les binaires Lua sont fournis par la plupart des distributions GNU/Linux sous forme de paquet.

Par exemple, sur Debian, Ubuntu et leurs dérivés, il peut être acquis en exécutant ceci :

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

Il existe des versions semi-officielles fournies pour Windows, MacOS et d’autres systèmes d’exploitation hébergés sur [SourceForge] (http://luabinaries.sourceforge.net/).

Les utilisateurs d’Apple peuvent également installer Lua facilement en utilisant Homebrew :

brew install lua

(Actuellement, Homebrew a 5.2.4, pour 5.3 voir Homebrew/versions.)

La source

La source est disponible sur la page officielle. L’acquisition de sources et la construction elle-même devraient être triviales. Sur les systèmes Linux, ce qui suit devrait suffire :

$ 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

Dans l’exemple ci-dessus, nous téléchargeons essentiellement une source tarball depuis le site officiel, vérifions sa somme de contrôle, puis extrayons et exécutons make. (Vérifiez la somme de contrôle sur [la page officielle][1].)

Remarque : vous devez spécifier la cible de génération souhaitée. Dans l’exemple, nous avons spécifié linux. Les autres cibles de construction disponibles incluent solaris, aix, bsd, freebsd, macosx, mingw, etc. Consultez doc/readme.html, qui est inclus dans la source, pour plus d’informations. détails. (Vous pouvez également trouver [la dernière version du README en ligne][1].)

Modules

Les bibliothèques standards sont limitées aux primitives :

  • coroutine - fonctionnalité de gestion de la coroutine
  • debug - crochets et outils de débogage
  • io - primitives IO de base
  • package - fonctionnalité de gestion des modules
  • string - fonction de correspondance de chaînes et de modèles spécifiques à Lua
  • table - primitives pour traiter un type Lua essentiel mais complexe - tables
  • os - opérations de base du système d’exploitation
  • utf8 - primitives UTF-8 de base (depuis Lua 5.3)

Toutes ces bibliothèques peuvent être désactivées pour une version spécifique ou chargées au moment de l’exécution.

Les bibliothèques et l’infrastructure Lua tierces pour la distribution de modules sont rares, mais s’améliorent. Des projets comme LuaRocks, Lua Toolbox et LuaDist améliorent la situation. De nombreuses informations et de nombreuses suggestions peuvent être trouvées sur l’ancien [Lua Wiki] (http://lua-users.org/wiki/), mais sachez que certaines de ces informations sont assez anciennes et obsolètes.

[1] : https://www.lua.org/download.html

Commencer

variables

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.

les 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!"

Le type spécial “nil”

Un autre type en Lua est “nil”. La seule valeur dans le type nil est nil. ’nil’ existe pour être différent de toutes les autres valeurs en Lua. C’est une sorte de valeur sans valeur.

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!

expressions

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

Définition des fonctions

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

booléens

Seuls “false” et “nil” sont évalués comme faux, tout le reste, y compris “0” et la chaîne vide, sont évalués comme vrai.

collecte des ordures

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

les tables

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.

Ce sont les bases, mais il y a une section sur les tables avec plus d’informations.

les conditions

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

pour les boucles

Il existe deux types de boucle for en Lua : une boucle for numérique et une boucle for générique.

  • Une boucle for numérique a la forme suivante :

    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
    

    The third expression in a numeric for loop is the step by which the loop will increment. This makes it easy to do reverse loops:

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

    If the step expression is left out, Lua assumes a default step of 1.

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

    Also note that the loop variable is local to the for loop. It will not exist after the loop is over.

  • Les boucles for génériques fonctionnent sur toutes les valeurs renvoyées par une fonction d’itération :

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

Lua fournit plusieurs itérateurs intégrés (par exemple, pairs, ipairs), et les utilisateurs peuvent également définir leurs propres itérateurs personnalisés à utiliser avec des boucles for génériques.

faire des blocs

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

Quelques trucs délicats

Parfois, Lua ne se comporte pas comme on le penserait après avoir lu la documentation. Certains de ces cas sont :

Nil et Nothing ne sont pas pareils (PIEGE COMMUN !)

Comme prévu, table.insert(my_table, 20) ajoute la valeur 20 à la table, et table.insert(my_table, 5, 20) ajoute la valeur 20 à la 5ème position. Que fait table.insert(my_table, 5, nil) ? On pourrait s’attendre à ce qu’il traite ’nil’ comme aucun argument et insère la valeur ‘5’ à la fin du tableau, mais il ajoute en fait la valeur ’nil’ à la 5e position du tableau. Quand est-ce un problème ?

(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)

Une chose similaire se produit avec 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

Cela peut également entraîner des erreurs lors de l’utilisation d’un code tiers. Si, par exemple, la documentation de certaines fonctions indique “retourne des beignets si chanceux, nul sinon”, l’implémentation pourrait ressembler un peu à ceci

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

cette implémentation peut sembler raisonnable au premier abord ; il renvoie des beignets quand il le faut, et lorsque vous tapez result = func(false), le résultat contiendra la valeur nil.

Cependant, si l’on écrivait print(tostring(func(false))) lua lancerait une erreur qui ressemble un peu à celle-ci stdin:1: bad argument #1 to 'tostring' (valeur attendue)

Pourquoi donc? tostring obtient clairement un argument, même s’il est nil. Mauvais. func ne renvoie rien du tout, donc tostring(func(false)) est identique à tostring() et NON identique à tostring(nil).

Les erreurs disant “valeur attendue” sont une forte indication que cela pourrait être la source du problème.

Laisser des vides dans les tableaux

C’est un énorme piège si vous débutez avec lua, et il y a beaucoup d’[informations](https://www.wikiod.com/fr/lua/les-tables#Éviter les lacunes dans les tableaux utilisés comme tableaux as-arrays#t=20170113143427074516) dans la catégorie tables

Exécuter des programmes Lua

Habituellement, Lua est livré avec deux binaires :

  • lua - interpréteur autonome et shell interactif
  • luac - compilateur de bytecode

Disons que nous avons un exemple de programme (bottles_of_mate.lua) comme celui-ci :

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

Le programme lui-même peut être exécuté en exécutant ce qui suit sur votre shell :

$ lua bottles_of_mate.lua

La sortie devrait ressembler à ceci, s’exécutant dans la boucle sans fin :

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.
...

Vous pouvez compiler le programme dans le bytecode de Lua en exécutant ce qui suit sur votre shell :

$ luac bottles_of_mate.lua -o bottles_of_mate.luac

La liste des bytecodes est également disponible en exécutant ce qui suit :

$ 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

Bonjour le monde

C’est bonjour le code mondial :

print("Hello World!")

Comment ça fonctionne? C’est simple! Lua exécute la fonction print() et utilise la chaîne "Hello World" comme argument.