Les expressions en LUA
Définition Expressions arithmétiques Expressions de comparaison Opérateurs logiques Opérateurs ternaires Les expressions conditionnelles et la valeur nil
Définition
Les expressions en LUA sont évaluées afin d'exécuter les calculs pour affecteer des valeurs aux variables ou pour passer des arguments aux fonctions.
Nous emploierons = la notation racourcie dans ce document. Les valeurs peuvent facilement être assignées à une variable, par exemple,
> x = 7 > print(x) 7 > = 7 7
Expressions arithmétiques
Lua utilise les opérateurs habituels d'arithmétique binaire. > = 2+3, 5-12, 2*7, 7/8 5 -7 14 0.875 > = 5*(2-8.3)/77.7+99.1 98.694594594595 Négation unaire : > = -(-10), -(10) 10 -10 Puissance de : > = 7^2, 107^0, 2^8 49 1 256
Expressions de comparaison
On fournit des opérateurs relationnelles qui renvoient les valeurs booléennes true ou false.
== égale à
~= pas égale à
< moins que
> plus grand que
<= inférieur ou égal à
>= supérieur ou égal à
> = 1 == 1, 1 == 0 true false > = 1 ~= 1, 1 ~= 0 false true > = 2 < 7, 2 > 7 true false > = 3 <= 7, 7 <= 7, 8 <= 7 true true false
> = 3 >= 7, 7 >= 7, 8 >= 7 false true true
Ceux-ci opérent également sur des chaînes de caractères et d'autres types. > = "abc" < "def" true > = "abc" > "def" false > = "abc" == "abc" true > = "abc" == "a".."bc" true
Les objets ne seront pas égaux si les types sont différents ou se rapportent à différents objets.
> = {} == "table" false
> = {} == {} -- two different tables are created here false
> t = {} > t2 = t
> = t == t2 -- we're referencing the same table here true
La coercition ne fonctionne pas ici, les types doivent être convertis explicitement. Voir Nombres et Chaînes pour l'explication de la coercition.
> = "10" == 10 false
> = tonumber("10") == 10 true
Opérateurs logiques
Lua dispose des opérateurs logiques and, or et not. En Lua tous nil et valeur
booléenne false représentent false (faux) dans une expression logique. Quelque chose qui n'est pas faux (l'un ou l'autre nilou false) est true (vrai). Il y a plus de notes sur les implications de ceci à la fin de cette page.
> = false==nil -- although they represent the same thing they are not equivalent false
> = true==false, true~=false false true
> = 1==0 false
> = does_this_exist -- test to see if variable "does_this_exist" exists. no, false. nil
Le mot-clé not inverse une valeur logique d'expression : > = true, false, not true, not false
true false false true
> = not nil -- nil represents false true
> = not not true -- true is not not true! true
> = not "foo" -- anything not false or nil is true false
and - (et)
L'opérateur binaire and ne renvoie pas nécessairement une valeur
booléenne true ou false à l'expression logique X et y. Dans certains languages,
l'opérateur and retourne une valeur booléenne dépendante des deux valeurs entrées. Par contre dans Lua, elle renvoie le premier argument si sa valeur est false ou nil, et le deuxième argument si le premier argument n'était pas faux. Ainsi, un booléen est seulement retourné si les valeurs passées étaient booléen.
> = false and true -- false is returned because it is the first argument false
> = nil and true -- as above nil
> = nil and false nil
> = nil and "hello", false and "hello" nil false
Toutes les expressions ci-dessus renvoient le premier argument. Toutes les expressions suivantes renvoient le deuxième argument, car le premier est vrai.
> = true and false false
> = true and true true
> = 1 and "hello", "hello" and "there" hello there
> = true and nil nil
Comme vous pouvez voir que les expressions logiques sont encore évaluées correctement mais nous avons un comportement intéressant en raison des valeurs retournées.
or - (ou)
or L'opérateur binaire également ne renvoie pas nécessairement une valeur booléenne
(voir les notes pour and ci-dessus). Si le premier argument n'est pas faux il est retourné, autrement le deuxième argument est retourné.
> = true or false true > = true or nil true > = "hello" or "there", 1 or 0 hello 1
Ceci peut être une propriété très utile. Par exemple, plaçant des valeurs par défaut dans une fonction :
> function foo(x)
>> local value = x or "default" -- if argument x is false or nil, value becomes "default" >> print(value, x)
>> end >
> foo() -- no arguments, so x is nil default nil > foo(1) 1 1 > foo(true) true true > foo("hello") hello hello
Opérateurs ternaires
Les opérateurs ternaires sont un dispositif utile dans le C. par exemple. int value = x>3 ? 1 : 0;
Ce comportement peut être partiellement émulé dans Lua en utilisant les opérateurs logiques and et or. La forme de C :
value = test ? x : y; traduit en Lua : value = test and x or y Par exemple.
> print( 3>1 and 1 or 0 ) 1
> print( 3<1 and 1 or 0 ) 0
> print( 3<1 and "True" or "False" ) False
> print( 3>1 and true or "false" ) true
Cependant, il y a une limite, ceci fonctionne seulement quand la première valeur de retour n'est pas nil ou false.
> print( 3>1 and 1 or "False" ) -- works 1
> print( 3>1 and false or "oops" ) -- failed, should return false oops
> print( 3>1 and nil or "oops" ) -- failed, should return nil oops
Les expressions conditionnelles et la valeur nil
Un point important à noter est que la valeur 0 n'est pas une condition d'essai fausse dans Lua. Dans d'autre langage, par exemple C, un test :
if (0)
printf("true"); else
montrerait "false". Dans Lua, > if 0 then >> print("true") >> else >> print("false") >> end true affiche "true".
Vous devriez employer false, ou nil au lieu de 0 : > if false then print("true") else print("false") end false
> if nil then print("true") else print("false") end false
Pourquoi ?
La raison de ceci est historique. Lua n'a pas soutenu les types booléens
(c.-à-d. true et false) avant la version 5.0. Avant la version 5.0 une valeur nil représentatit false (faux). Maintenant, tous les deux nil et false agiront en tant qu'état faux dans une expression conditionnelle. Par exemple,
> if nil then print("true") else print("false") end false
> if 1 then print("true") else print("false") end true
> if 0 then print("true") else print("false") end true
> if 1==2 then print("true") else print("false") end false
Un autre point à noter est celui true et false ne sont des valeurs numériques, par exemple, 1 et 0 comme dans d'autres languages.
> = true, false true false > = 1 + true
stdin:1: attempt to perform arithmetic on a boolean value stack traceback:
stdin:1: in main chunk [C]: ?
En outre, nil est forcé à une valeur booléenne une fois utilisé avec un opérateur logique : > = not nil true > = not 1 false > = not 0 false
Définir des fonctions Déclarations de fonction Arguments
Fonctions anonymes Destruction de fonction
Définir des fonctions
Des fonctions peuvent être définies en utilisant le mot-clé function . Il y a deux variations dans la manière de déclarer des fonctions :
function function_name (argument) corps end
est le même que :
function_name = function( arguments ) corps end
Ce qui suit est un exemple d'une fonction simple pour doubler un nombre : > function foo(n) return n*2 end
> = foo(7) 14
Nous définissons une fonction appelée "foo" qui prend un argument simple et renvoie deux fois sa valeur. La fonction ci-dessus pourrait également avoir été écrite :
> foo = function(n) return n*2 end > = foo(4)
8
Quand nous définissons une fonction, vous pourriez dire que nous assignons un corps de fonction à une variable. Cette capacité à traiter des fonctions comme nous traiterions tout autre objet que nous pouvons affecter à une variable , implique que les fonctions
soient des valeurs de première classe. La variable à laquelle est affectée une fonction a le type fonction. Nous n'avons pas à indiquer un type complexe de fonction à la variable, comme par exemple en utilisant les pointeurs de fonction en C qui contiennent l'argument et le type de l'information de retour.
Déclarations de fonction
Dans Lua vous n'avez pas besoin de déclarer des types pour des valeurs retournées par des fonctions ou pour des arguments passés aux fonctions !
Lua est un langage avec un typage dynamique avec les objets de première classe. Ceci signifie que nous découvrons seulement si quelque chose est une fonction quand nous essayons de l'exécuter. Les languages typés statiquement (comme C) doivent connaître les types des variables lors de la compilation.
> x = "onion" > x()
stdin:1: attempt to call global `x' (a string value) stack traceback:
stdin:1: in main chunk [C]: ?
Nous ne pourrions pas appeler l'objet x parce que c'est une chaîne de caractères. Quand nous assignons la fonction foo à la variable x, nous pouvons l'appeler (comme dans l'exemple précédent).
Remarquez ci-dessous la simplicité de la déclarations de la fonction ou ne devons pas dire à Lua que foo est une fonction.
> x = foo > = x(77) 154
Nous n'avons aucun problème affecter des fonctions de différents types à la variable x puisque x n'a aucune notion du type de l'objet qu'il lui est affecté. > x = function(a,b) return a+b end
> = x(5,6) 11
> function x(a,b) return a..b end > = x('a','b')
ab
Naturellement nous devons faire attention à ne pas appeler accidentellement des variables de la même manière, car nous n'aurions pas d'erreurs explicites comme dans des
languages typés statiquement Cependant, cette fonctionnalité est très utile et nous permet d'écrire du code très flexible et très simplement.
Arguments
Puisque Lua n'a aucune déclaration de fonction il doit traiter des arguments de fonction et des valeurs de retour d'une façon flexible. Lua supporte des arguments multiples, des liste d'arguments variables et des valeurs de retour multiples. Ceci est couvert en plus détail dans Appel de Fonctions.
Fonctions anonymes
Il est parfois utile de définir des fonctions pour exécuter une tâche sans leur donner un nom en les assignant à une variable.
Nous insérerons une définition de fonction dans une modification de l'exemple ci-dessus. Nous définirons une fonction pour passer table.foreach() à ce qui pour la liste variable d'argument montre chaque clef, sa valeur et le type de l'objet de valeur :
> function foo(...) >> table.foreach(arg, function(key,value) >> print(key,value,type(value)) >> end) >> end -- foo > foo("apple",2,"banana",3.1415927,foo) 1 apple string 2 2 number 3 banana string 4 3.1415927 number
5 function: 004419E8 function n 5 number
Remarquez que la fonction n'a aucun nom : function(key,value)
print(key,value,type(value)) end
Ceci s'appelle une fonction anonyme. La fonction est définie et au lieu d'être affecté à une variable, une référence est passée comme argument table.foreach.
Destruction de fonction
Dans l'exemple suivant nous créons une fonction appelée "foo", qui comme nous pouvons voir a le type "function" :
> function foo() >> print("foo!") >> end > > foo() foo!
> = type(foo) -- what type is foo? function
Puisque foo est juste une référence à un corps de fonction nous pouvons affecter d'autres variables pour avoir la même valeur. Nous pouvons également supprimer la référence à foo pour lui affecter la valeur nil . Ceci supprime efficacement la variable foo . > bar = foo -- copy foo's reference to another variable
> foo = nil -- delete the reference to the function body > = foo
nil
> foo() -- try to invoke the function
stdin:1: attempt to call global `foo' (a nil value) stack traceback:
stdin:1: in main chunk [C]: ?
Remarque, si la variable pointe sur le corps de fonction que nous l'avons défini elle sera inaccessible, et sera supprimée (voir Garbage Collection). Dans ce cas nous avons affecté le corps de fonction à la variable bar, ainsi d'une manière nous avons renommé la fonction. Mais quand nous plaçons la variable bar à nil, il n'y a aucune autre variable pointant sur le corps de fonction, et il sera supprimé quand le garbage collector sera appelé.
> bar() -- bar still points to the same function that foo did foo!
> bar = nil -- now nothing points to the function so it can be garbage collected
Remarquez que nous n'avons pas dû indiquer les types de fonction, ni nous inquiéter de la façon dont les arguments seront passés. C'est parce que Lua est un language typé
dynamiquement où une variable peut pointer sur un objet de n'importe quel type. La variable est juste une référence à un objet et le type vient de l'objet référencé.
Instructions de sélection
tant que ... faire ... - (while..do...)répéter ... jusqu'à... - (repeat...until...) pour ... faire... - (for...do...)
si ... alors ...ou alors ... sinon... - (If .. then ...elseif...else)
Les structures de commande de Lua seront familiers aux programmeurs. Les expressions conditionnelles mentionnées ("exp") sur cette page sont aussi abordées au
chapître Expressions. Veuillez lire préalablement la note sur les valeur nil Expressions.
Tant que ... faire ... - (while..do...)
L'expression de boucle conditionnel while a la forme :
while condition do instruction end
Elle s'interprète de la façon suivante: Tant que la condition n'est pas satisfaite exécuter l'instruction
Par exemple, une boucle simple : i = 3 > while i>0 do >> print(i) >> i = i-1 >> end 3 2 1
Nous pouvons quitter la boucle de while en utilisant le mot-clé break . Notez, dans Lua que le mot-clé break doit être le dernier mot dans un bloc, c.-à-d. que le mot-clé end doit le suivre. Vous obtiendrez des erreurs de compilation si vous n'avez pas break end. a,b = 0,1
> while true do -- infinite loop >> io.write(b, ", ")
>> a,b = b,a+b
>> if a>500 then break end -- exit the loop if the condition is true >> end
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, >
Répéter ... jusqu'à... - (repeat...until...)
L'expression faisant une boucle conditionnel repeat a la forme :
repeat instruction until condition
Elle s'interprète de la façon suivante: Répéter l'instruction tant que la condition n'est pas satisfaite
Par exemple, une boucle simple : i = 3 > repeat >> print(i) >> i = i-1 >> until i==0 3 2 1
Comme por l'expression while nous pouvons quiiter la boucle repeat utilisant break: > i = 1
> repeat >> print(i) >> i = i+1
>> if i>3 then break end >> until cows_come_home 1
2 3
cows_come_home est une variable qui n'est pas définie. Quand nous l'accédons nous
obtenons la valeur nil, qui signifie "jusqu'à faux", ou pour toujours.
Pour ... faire... - (for...do...)
Elle s'interprète de la façon suivante: Pour les valeurs précisées faire l'instruction l'expression de réitération for a deux formes.
Le premier est pour l'itération numérique, par exemple, > for count = 1,3 do print(count) end -- numerical iteration 1
2 3
La seconde est pour l'itération séquentielle, par exemple imprimer le contenu d'une table :
> for key,value in {10, math.pi, "banana"} do print(key, value) end 1 10
2 3.1415926535898 3 banana
L'exemple ci-dessus est modifié avce une combinaison de syntaxe pour l'exemple
suivant. for est passé à une fonction d'iteration, qui est ici la fonction pairs(), dont le but il est de fournir les valeurs de chaque itération :
> for key,value in pairs({10, math.pi, "banana"}) do print(key, value) end 1 10
2 3.1415926535898 3 banana
Il y a plus de détail sur toutes les formes de for au chapître Boucle For.
Si ... alors ... ou si ... alors ... sinon... - (If .. then ...elseif...else)
l'expression if a la forme :if condition_1 then instruction_1 { elseif condition_x then instruction_x}
[ else instruction_2 ] end
Elle s'interprète de la façon suivante: Si la condition_1 est satisfaite exécuter l'instruction_1 ou si la condition_x est satisfaite alors exécuter
l'instruction_x sinon exécuter l'instruction_2 Par exemple if ... then ... end
if 10>2 then print("bigger") end bigger
> if 1>10 then print("bigger") else print("smaller") end smaller
if ... then ... elseif ... else ... end
> number = 3 > if number < 1 then
>> value = "smaller than one" >> elseif number==1 then >> value = "one"
>> elseif number==2 then >> value = "two"
>> elseif number==3 then >> value = "three"
>> else
>> value = "bigger than three" >> end
> print(value) three
Itération avec for
Progression numérique Iterations o Itération de tables o Fonction pairs(table) o Fonction ipairs(table) o Fonction: io.lines() o Fonction: file:lines()La boucle d'itération for est disponible sous deux formes. Une peut être employé pour réitérer par une progression numérique et l'autre peut être employé pour réitérer des fonctions finies appelées les iterators.
Progression numérique
La version numérique de progression de for a la syntaxe suivante :
for variable = from_expression , to_expression [, step_expression] do instruction end La boucle d'itération for positionne la valeur variable à from_exp avant d'éxécuter l'intruction. L'intruction est exécutée seulement si la variable n'a pas passé la dernière valeur de to_exp. Ceci inclut la première fois que la boucle est réitérée. Chaque fois que instruction est exécuter step_exp est ajouté à la variable. L'indication de step_exp est facultative. Si on ne l'indique pas la valeur de 1 est employée. Par exemple,
> for i = 1,3 do print(i) end -- count from 1 to 3 1
2 3
> for i = 3,1 do print(i) end -- count from 3 to 1 in steps of 1. zero iterations! > for i = 3,1,-1 do print(i) end -- count down from 3 to 1
3 2 1
> for i=1,0,-0.25 do print(i) end -- we're not limited to integers 1
0.75 0.5
0.25 0
for i = e1,e2,e3 do end est équivalent au code suivant de Lua :
do
local i, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) or 1 if not (i and limit and step) then error() end
while (step>0 and i<=limit) or (step<=0 and i>=limit) do -- block code
i = i + step end
end
Iterations
La deuxième forme de la boucle for a la syntaxe : for var {, var} in explist do block end
l'explist (liste d'expressions) est évalué avant l'entrée dans la boucle. Les résultats de cette évaluation sont une fonction
iterative (qui place les valeurs de var), un état (d'ou les valeurs peuvent être lues), et une valeur initiale (d'ou part l'itération).
Itération de tables
Si nous mettions une table au lieu d'explist Lua fournira l'explist correct pour nous. Chaque élément dans une table est représenté par une paire de clef et de valeur. Lisez Table pour plus de détails au sujet de l'utilisation des tables. Pourafficher tous les éléments dans une table nous pouvons faire ce qui suit :
t = { 3,7,10,17; banana="yellow", pi=3.14159 } > for key,value in t do print(key,value) end 1 3 2 7 3 10 4 17 pi 3.14159 banana yellow Fonction: pairs(table)
Lua fournit une fonction pairs() pour créer l'information d'explist pour itèration d'une table. La fonction pairs()permettra l'itération sur les paires de clef-valeur.
for key,value in pairs(t) do print(key,value) end 1 3 2 7 3 10 4 17 pi 3.14159 banana yellow Fonction: ipairs(table)
ipairs() La fonction permettra l'itération sur des paires d'index-valeur. Ce sont des
> for index,value in ipairs(t) do print(index,value) end 1 3
2 7 3 10 4 17
Remarquez comment seulement la rangée de la table est affiché parce que seulement ces éléments ont des clefs d'index.
Fonction: next()
La fonction next(table [,index]) réalise une itèration sur une table. Avce une table et un index elle renvoie la prochaine paire de clef-valeur de la table, par exemple,
= next(t) -- index will be nil, the beginning 1 3
> = next(t,"pi") banana yellow
pairs() La fonction renvoie un explist (liste d'expressions) contenant next() ainsi nous
pouvons faire une itération sur les tables. Nous pouvons passer notre propre liste d'expression à la condition forcomme suit :
> for key,value in next,t,nil do print(key,value) end 1 3 2 7 3 10 4 17 pi 3.14159 banana yellow
Nous passons next,table,nil comme liste d'expression à la condition for . Nous disons ici que nous voulons employer la fonction d'iteration next(), sur la table appelée la "table", commençant à nil (le commencement). La condition for continue à s'exécuter jusqu'à ce que la fonction next() retourne nil (l'extrémité de la table).
Fonction: io.lines()
Lua fournit d'autres iteration utiles, comme io.lines([filename]) dans la
bibliothèque io. Nous pouvons démontrer ceci en créant un dossier fait sur commande contenant quelques lignes de texte.
io.output(io.open("my.txt","w"))
> io.write("This is\nsome sample text\nfor Lua.") > io.close()
Fonction: file:lines()
La bibliothèque io fournit une autre manière de lire les lignes de texte d'un fichier. > for line in io.lines("my.txt") do print(line) end
This is
some sample text for Lua.
> file = assert(io.open("my.txt", "r")) > for line in file:lines() do print(line) end This is
some sample text for Lua.
> file:close()
Quelles sont les différences avec io.lines()?
Vous devez explicitement ouvrir et fermez le ficheir. Un des avantage est que si le dossier ne peut pas être ouvert, vous pouvez gérer cet échec dans le code. Ici, assert a le même effet que io.lines: l'interprèteur LUA s'arrête avec un message d'erreur et pointe sur la ligne défectueuse ; mais vous pouvez tester sur la valeur nil de file et faire autre chose. Un autre avantage est que vous pouvez commencer la boucle sur n'importe quelle ligne : file = assert(io.open("list.txt", "r"))
local line = file:read()
if string.sub(line, 1, 1) ~= '#' then
ProcessLine(line) -- File doesn't start with a comment, process the first line end
-- We could also loop on the first lines, while they are comment -- Process the remainder of the file
for line in file:lines() do ProcessLine(line) end
file:close()
Iterators faits sur commande
Nous pouvons écrire nos propres iterations, similaires à next(), pour réaliser des itérations sur des séquences quelconques de données. Ceci est couvert plus en détail dans Iterations.