Bases
Hello World
print ajoute un saut de ligne automatiquement
-- comments start with --
print("Hello, World!")
-- variables (global by default)
x = 10
name = "Alice"
-- local variables
local y = 20
local z = x + y
-- multiple assignment
local a, b, c = 1, 2, 3
print(a, b, c) -- 1 2 3Commentaires
--[[ ]] pour les commentaires multi-lignes
-- single line comment
--[[ multi-line
comment block ]]
print("hi")
-- long-bracket comments can have = signs for nesting
--[==[ this is a comment with ]] inside ]==]
print("still runs")Points-virgules optionnels
Les points-virgules sont optionnels
print("Hello") -- prints with a trailing newline
io.write("no newline") -- writes without a newline
-- print separates multiple args with tabs
print("name", "age") -- name age
-- print converts all types (nil included)
print(42, true, nil) -- 42 true nil
-- io.stdout / io.stderr are file handles
io.stderr:write("warning\n")Assignation multiple
Supporte l'assignation simultanée à plusieurs variables
local a, b = 1, 2
print(a, b) -- 1 2
a, b = b, a -- swap without a temp variable
print(a, b) -- 2 1
local x, y, z = 10 -- y, z become nil
local m, n = 1, 2, 3 -- 3 is discarded
print(m, n) -- 1 2Mode interactif
lua -i entre en mode interactif
-- run the REPL: lua -i
-- run a file: lua script.lua
-- show the version: lua -v
-- inside the REPL:
-- > print("hi")
-- hi
-- > = 2 + 3 -- '=' prints an expression value
-- 5
-- > = string.rep("ab", 3)
-- abababnil & Variable Deletion
nil is Lua's only 'no value' type. Assigning nil to a table key deletes it. Accessing undeclared globals returns nil rather than raising an error, which can mask typos—use strict.lua to catch them.
local x = 10
print(x) -- 10
x = nil -- delete the value
print(x) -- nil
if x == nil then
print("x is nil")
end
-- reading an undeclared name returns nil (no error)
print(undefined_var) -- nil
-- assign nil to let the GC collect a table entry
local t = {a = 1}
t.a = nilVariables
Variables local
local déclare des variables locales
-- Lua has 8 basic types:
print(type(nil)) -- nil
print(type(true)) -- boolean
print(type(42)) -- number
print(type("hi")) -- string
print(type({})) -- table
print(type(print)) -- function
print(type(coroutine.create(function() end))) -- thread
print(type(io.stdin)) -- userdata
-- type() always returns a string
print(type(type(42))) -- stringVariables globales
Sans local, c'est une variable globale
-- Lua 5.3+ distinguishes integers and floats
local i = 10 -- integer
local f = 3.14 -- float
print(type(i), math.type(i)) -- number integer
print(type(f), math.type(f)) -- number float
local hex = 0xFF -- 255
local exp = 1e3 -- 1000.0 (float)
print(hex, exp)
-- integer / integer with no fraction stays integer
print(7 / 2) -- 3.5 (true division, always float)
print(7 // 2) -- 3 (floor division)Assignation multiple
Les valeurs manquantes deviennent nil, les extras sont ignorés
local s1 = "double quoted"
local s2 = 'single quoted' -- identical to double
local s3 = [[
a multi-line
string, escapes ignored]]
print(#s1) -- 14 (# is the length operator)
print(s1:upper()) -- DOUBLE QUOTED
-- strings are immutable: operations return new stringsÉchange de variables
Aucune variable temporaire nécessaire
local flag = true
local done = false
-- ONLY nil and false are falsy
-- 0, "", and {} are all truthy (unlike many languages)
if 0 then print("0 is truthy") end
if "" then print("empty string is truthy") end
-- logical operators short-circuit and return a value
local x = nil or "default" -- "default"
local y = true and "yes" -- "yes"
print(x, y)Suppression de variables
Assigner nil permet au GC de récupérer
-- the table is Lua's only composite data structure
-- it serves as array, dictionary, object, and module
local arr = {10, 20, 30} -- array (1-indexed)
local dict = {name = "Lua", ver = 5.4}
local mixed = {1, 2, x = 3}
print(arr[1]) -- 10 (indices start at 1, not 0)
print(dict.name) -- Lua
print(mixed.x) -- 3
print(#arr) -- 3Type Checks
type() is the standard way to branch on a value's type. It returns 'nil' for nil rather than erroring. For finer checks use math.type (int vs float) or rawequal for identity comparison.
local function describe(v)
local t = type(v)
if t == "table" then
return "a table"
elseif t == "string" then
return "a string: " .. v
elseif t == "nil" then
return "nothing"
end
return "a " .. t
end
print(describe({})) -- a table
print(describe("hi")) -- a string: hi
print(describe(nil)) -- nothingTypes de données
Types de base
Lua a 8 types de base
print(10 + 3) -- 13
print(10 - 3) -- 7
print(10 * 3) -- 30
print(10 / 3) -- 3.3333... (true division)
print(10 % 3) -- 1 (modulo)
print(2 ^ 10) -- 1024.0 (^ is exponent, NOT xor)
print(-5) -- -5 (unary minus)Nombres
Lua 5.3+ distingue les entiers et les flottants
-- Lua 5.3+ integer floor division
print(10 // 3) -- 3 (integer)
print(-10 // 3) -- -4 (floors toward -inf)
print(10.0 // 3) -- 3.0 (float floor div)
-- modulo result takes the sign of the divisor
print(10 % 3) -- 1
print(-10 % 3) -- 2
print(10 % -3) -- -2Chaînes de caractères
# obtient la longueur de la chaîne
print(3 == 3) -- true (equality)
print(3 ~= 4) -- true (inequality: ~=, not !=)
print(3 < 4) -- true
print(3 > 4) -- false
print(3 <= 3) -- true
print(3 >= 4) -- false
print("abc" < "abd") -- true (lexicographic)
print(1 == "1") -- false (different types never equal)Booléens
0 et la chaîne vide sont truthy
-- and / or / not short-circuit and return a value (not a bool)
print(true and 10) -- 10
print(false or "x") -- "x"
print(nil or "default") -- "default"
print(not nil) -- true
-- idiom for defaults
local name = nil
local display = name or "anonymous"
-- ternary-like (beware falsy 'false' values!)
local v = (cond) and "yes" or "no"Tables
table est la seule structure de données composite
local name = "Lua"
local v = 5.4
print("Hello " .. name .. " " .. v) -- Hello Lua 5.4
-- .. always creates a new string
local s = "a" .. "b" .. "c"
print(s) -- abc
-- numbers are auto-converted when concatenated
print("n=" .. 42) -- n=42
-- repeat a string with string.rep
print(string.rep("ab", 3)) -- abababLength Operator
# returns the byte length of a string or the length of a table's sequence part. It is only well-defined for tables without holes (nil gaps). For UTF-8 character counts use lua-utf8 or the utf8 library (Lua 5.3+).
-- # works on strings and the sequence part of tables
print(#"hello") -- 5
print(#{10, 20, 30}) -- 3
-- caution: # only counts the contiguous sequence part
-- the result is UNDEFINED if the table has holes
local t = {1, 2, nil, 4}
print(#t) -- 2 or 4 (implementation-defined)
-- # on a string returns its byte length, not codepoints
print(#"cafe") -- 4
print(#"café") -- 5 (é is 2 bytes in UTF-8)Opérateurs
Opérateurs arithmétiques
^ est l'exponentiation, pas le XOR
local score = 85
if score >= 90 then
print("A")
elseif score >= 80 then
print("B")
elseif score >= 70 then
print("C")
else
print("F")
end
-- keywords: if / then / elseif / else / end
-- parentheses around the condition are optionalDivision entière
// est la division entière
local i = 1
while i <= 5 do
print(i)
i = i + 1 -- Lua has no ++ operator
end
-- the condition is checked before each iteration
local n = 0
while n < 3 do
print("loop", n)
n = n + 1
endOpérateurs de comparaison
~= signifie différent de
-- repeat-until runs the body at least once (like do-while)
-- the loop STOPS when the condition becomes true
local i = 1
repeat
print(i)
i = i + 1
until i > 5
-- the condition can see locals declared in the body
local x
repeat
x = math.random(1, 10)
until x == 7Opérateurs logiques
and/or supportent l'évaluation en court-circuit
-- for start, stop[, step]
for i = 1, 5 do
print(i) -- 1 2 3 4 5
end
for i = 10, 1, -2 do
print(i) -- 10 8 6 4 2
end
-- step defaults to 1; the loop variable is local to the loop
for i = 1, 3 do print(i) end
-- print(i) -- i is out of scope hereConcaténation de chaînes
.. concatène les chaînes
local arr = {"a", "b", "c"}
-- ipairs iterates the array (sequence) part, 1..n
for i, v in ipairs(arr) do
print(i, v) -- 1 a / 2 b / 3 c
end
local dict = {x = 1, y = 2}
-- pairs iterates ALL key/value pairs (order not guaranteed)
for k, v in pairs(dict) do
print(k, v)
endOpérateur de longueur
# obtient la longueur d'une chaîne ou d'une table
-- break exits the innermost loop only
for i = 1, 10 do
if i == 5 then break end
print(i) -- 1 2 3 4
end
-- Lua has NO continue; emulate it with goto
for i = 1, 5 do
if i % 2 == 0 then goto continue end
print(i) -- 1 3 5
::continue::
end
-- goto jumps to a label ::name:: within the same scopeFlux de contrôle
if-elseif-else
Notez les mots-clés then et end
local s1 = "double 'quoted'"
local s2 = 'single "quoted"'
local s3 = "line1\nline2\ttabbed"
local s4 = "percent: %d %%"
-- long brackets: escapes are NOT processed
local s5 = [[raw \n string, \t kept literal]]
print(s3, s5)Boucle while
while-do-end
local s = "hello"
print(#s) -- 5 (byte length)
-- the string library is 1-indexed
print(s:sub(1, 3)) -- "hel"
print(s:sub(-2)) -- "lo" (negative = from end)
print(s:byte(1)) -- 104 (ASCII of 'h')
print(string.char(104, 105)) -- "hi"repeat-until
Comme do-while, quitte quand la condition est vraie
-- [[ ]] preserves newlines exactly
local text = [[Line 1
Line 2
Line 3]]
print(text)
-- match bracket level to allow ]] inside
local code = [==[
if a then ]] -- this ]] is literal
end ]==]
print(code)for numérique
for start, stop, step
local n = tonumber("42") -- 42 (number)
local f = tonumber("3.14") -- 3.14
local bad = tonumber("abc") -- nil (no error raised)
local s = tostring(42) -- "42"
local b = tostring(true) -- "true"
local nil_s = tostring(nil) -- "nil"
print(tonumber("0x1F")) -- 31 (hex)
print(tonumber("11", 2)) -- 3 (base 2)for générique
ipairs itère les tableaux, pairs itère tout
-- string.format uses C-style format strings
print(string.format("%d + %d = %d", 2, 3, 5)) -- 2 + 3 = 5
print(string.format("%.2f", 3.14159)) -- 3.14
print(string.format("%5d", 42)) -- " 42"
print(string.format("%-10s|", "hi")) -- "hi |"
print(string.format("%x %o", 255, 8)) -- ff 10break
Lua n'a pas de continue
local s = "Hello, World"
-- s:method(x) is sugar for string.method(s, x)
print(s:upper()) -- HELLO, WORLD
print(s:lower()) -- hello, world
print(s:rep(2)) -- Hello, WorldHello, World
print(s:reverse()) -- dlroW ,olleH
print(s:sub(1, 5)) -- Hello
print(s:find("World")) -- 8 13 (start and end indices)Fonctions
Définition de fonction
local function définit une fonction locale
-- array (sequence)
local arr = {10, 20, 30, 40}
-- dictionary (hash)
local p = {name = "Lua", version = 5.4}
-- mixed: both sequence and hash entries
local m = {1, 2, 3, lang = "Lua"}
print(arr[1]) -- 10 (1-indexed!)
print(p.name) -- Lua
print(p["version"]) -- 5.4
print(#arr) -- 4Valeurs de retour multiples
Les fonctions peuvent renvoyer plusieurs valeurs
local t = {name = "Lua", ["full name"] = "Lua 5.4"}
-- dot notation works only for valid identifiers
print(t.name) -- Lua
-- bracket notation works for any string key
print(t["full name"]) -- Lua 5.4
-- bracket form accepts variables
local key = "name"
print(t[key]) -- Lua
t.name = "LuaLang"
t["new key"] = 99Fonctions variadiques
... représente les arguments variadiques
local t = {10, 20, 30}
table.insert(t, 40) -- append: {10,20,30,40}
table.insert(t, 1, 5) -- insert at index 1: {5,10,20,30,40}
print(#t) -- 5
local removed = table.remove(t) -- pop last: 40
local first = table.remove(t, 1) -- remove index 1: 5
print(removed, first, #t) -- 40 5 3
-- table.move(src, f, e, t[, dst]) (Lua 5.3+)
local src = {1, 2, 3, 4, 5}
table.move(src, 2, 4, 1) -- copy elements 2..4 to position 1Fonctions anonymes
Les fonctions sont des citoyens de première classe
local nums = {5, 2, 8, 1, 9}
table.sort(nums)
print(table.concat(nums, ",")) -- 1,2,5,8,9
-- custom comparator (return true if a should come before b)
local people = {
{name = "Bob", age = 30},
{name = "Ann", age = 25},
}
table.sort(people, function(a, b) return a.age < b.age end)
for _, p in ipairs(people) do print(p.name, p.age) end
-- Ann 25 / Bob 30Fonctions comme arguments
Fonctions d'ordre supérieur
local t = {10, 20, 30, name = "Lua"}
-- ipairs: sequence part, stops at the first nil
for i, v in ipairs(t) do
print(i, v) -- 1 10 / 2 20 / 3 30
end
-- pairs: every key/value pair (order not guaranteed)
for k, v in pairs(t) do
print(k, v) -- includes name Lua (order varies)
end
-- numeric loop over the sequence
for i = 1, #t do print(t[i]) endTable Length & Nested Tables
Tables nest naturally—matrix[r][c] indexes a row then a column. # on a nested table gives that row's length. table.concat efficiently joins a sequence of strings (and numbers) with a separator.
local matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
print(matrix[2][3]) -- 6 (row 2, col 3)
print(#matrix) -- 3 (number of rows)
print(#matrix[1]) -- 3 (number of cols)
-- table.concat joins an array of strings/numbers
print(table.concat({"a", "b", "c"}, "-")) -- a-b-c
print(table.concat({1, 2, 3}, "")) -- 123Tables
Création de tables
Les tables peuvent être utilisées comme tableaux et dictionnaires
-- named (global) function
function greet(name)
return "Hello, " .. name
end
-- local function (preferred)
local function add(a, b)
return a + b
end
print(greet("Lua")) -- Hello, Lua
print(add(2, 3)) -- 5
-- functions are first-class values
local f = add
print(f(10, 20)) -- 30Accès aux éléments
Deux méthodes d'accès : . et []
local function minmax(arr)
local lo, hi = arr[1], arr[1]
for _, v in ipairs(arr) do
if v < lo then lo = v end
if v > hi then hi = v end
end
return lo, hi
end
local mn, mx = minmax({3, 1, 4, 1, 5})
print(mn, mx) -- 1 5
-- values are adjusted: extras dropped, missing become nil
local a = minmax({2, 7}) -- a = 2 (mx discarded)Opérations sur les tableaux
la bibliothèque table fournit des opérations sur les tableaux
local function sum(...)
local total = 0
for _, v in ipairs({...}) do
total = total + v
end
return total
end
print(sum(1, 2, 3, 4)) -- 10
-- select('#', ...) = count; select(n, ...) = args from n
local function info(...)
print(select("#", ...)) -- number of args
print(select(2, ...)) -- args from position 2 onward
endTri
Fonction de comparaison personnalisée supportée
-- functions are first-class: assign to a variable
local double = function(x) return x * 2 end
print(double(21)) -- 42
-- as table fields
local ops = {
add = function(a, b) return a + b end,
mul = function(a, b) return a * b end,
}
print(ops.add(2, 3), ops.mul(2, 3)) -- 5 6
-- passed inline to higher-order functions
table.sort({3, 1, 2}, function(a, b) return a > b end)Itération
ipairs itère la partie tableau
local function map(arr, fn)
local result = {}
for i, v in ipairs(arr) do
result[i] = fn(v)
end
return result
end
local doubled = map({1, 2, 3}, function(x) return x * 2 end)
print(table.concat(doubled, ",")) -- 2,4,6
local function filter(arr, pred)
local out = {}
for _, v in ipairs(arr) do
if pred(v) then out[#out + 1] = v end
end
return out
endLongueur de table
# ne fonctionne que pour les tableaux contigus
-- Lua has no native named args; pass a table instead
local function create(opts)
opts = opts or {}
local name = opts.name or "anonymous"
local age = opts.age or 0
return {name = name, age = age}
end
-- call f{...} is sugar for f({...})
local p = create{name = "Alice", age = 30}
print(p.name, p.age) -- Alice 30Metatables
Définir une metatable
__index définit le comportement de recherche
local function make_counter()
local count = 0
return function()
count = count + 1
return count
end
end
local c = make_counter()
print(c()) -- 1
print(c()) -- 2
print(c()) -- 3
-- the inner function captures 'count' (an upvalue)Surcharge d'opérateurs
Peut surcharger les opérateurs comme + - * / == <
local function make_account(balance)
return {
deposit = function(n) balance = balance + n end,
withdraw = function(n) balance = balance - n end,
get = function() return balance end,
}
end
local acc = make_account(100)
acc.deposit(50)
acc.withdraw(30)
print(acc.get()) -- 120
-- 'balance' is private: only the methods can touch itHéritage __index
Héritage via __index
local function fibgen()
local a, b = 0, 1
return function()
a, b = b, a + b
return a
end
end
local next_fib = fibgen()
for i = 1, 8 do
io.write(next_fib(), " ") -- 1 1 2 3 5 8 13 21
end
print()__newindex
__newindex intercepte les assignations
local function memoize(fn)
local cache = {}
return function(x)
if cache[x] == nil then
cache[x] = fn(x)
end
return cache[x]
end
end
local function slow_square(n)
-- pretend this is expensive
return n * n
end
local fast_square = memoize(slow_square)
print(fast_square(5)) -- 25 (computed)
print(fast_square(5)) -- 25 (cached)__call
__call permet à une table d'être appelée comme une fonction
local function adder(x)
-- 'x' is an upvalue for the returned function
return function(y) return x + y end
end
local add5 = adder(5)
local add10 = adder(10)
print(add5(3)) -- 8
print(add10(3)) -- 13
-- each call to adder creates a separate upvalue
-- block scope with do-end
do
local tmp = "hidden"
end
-- print(tmp) -- error: tmp is out of scopePOO
Simulation de classe
Simuler des classes avec des tables et metatables
local t = {}
local mt = {}
setmetatable(t, mt)
print(getmetatable(t) == mt) -- true
-- setmetatable returns the table, so chain inline
local t2 = setmetatable({key = 1}, {
__tostring = function(self) return "MyTable" end,
})
print(tostring(t2)) -- MyTableCréation d'objet
: l'appel passe automatiquement self
local defaults = {color = "red", size = 10}
local obj = {color = "blue"}
setmetatable(obj, {__index = defaults})
print(obj.color) -- blue (own key wins)
print(obj.size) -- 10 (falls back to defaults)
print(obj.shape) -- nil (not found anywhere)
-- __index can also be a function: __index = function(t, k) ...Héritage
Héritage via la chaîne de metatables
local log = {}
local t = setmetatable({}, {
__newindex = function(t, k, v)
log[k] = v -- record the assignment
rawset(t, k, v) -- actually store it (avoid recursion)
end,
})
t.x = 5 -- triggers __newindex
print(log.x, t.x) -- 5 5
-- rawset/rawget bypass metamethodsRedéfinition de méthode
La méthode de la sous-classe redéfinit celle du parent
local Vec = {}
Vec.__index = Vec
Vec.__add = function(a, b) return Vec.new(a.x + b.x, a.y + b.y) end
Vec.__mul = function(a, n) return Vec.new(a.x * n, a.y * n) end
function Vec.new(x, y)
return setmetatable({x = x, y = y}, Vec)
end
local v1 = Vec.new(1, 2)
local v2 = Vec.new(3, 4)
local v3 = v1 + v2 -- uses __add
local v4 = v1 * 10 -- uses __mul
print(v3.x, v3.y) -- 4 6Comparison Metamethods
Comparison metamethods are __eq, __lt, and __le (Lua derives the others). They only apply when both operands share the same metamethod, and __eq requires both values to be of the same type.
local Money = {}
Money.__index = Money
Money.__lt = function(a, b) return a.cents < b.cents end
Money.__le = function(a, b) return a.cents <= b.cents end
Money.__eq = function(a, b) return a.cents == b.cents end
local function money(cents)
return setmetatable({cents = cents}, Money)
end
print(money(100) < money(200)) -- true
print(money(100) == money(100)) -- true__call & __tostring
__call makes a table callable as a function (great for functors and factories). __tostring controls how tostring() and print() render the table. Both dramatically improve the ergonomics of custom types.
local Greeter = {}
Greeter.__index = Greeter
Greeter.__call = function(self, who)
return "Hi " .. who .. ", I am " .. self.name
end
Greeter.__tostring = function(self)
return "Greeter(" .. self.name .. ")"
end
local g = setmetatable({name = "Bot"}, Greeter)
print(g("Alice")) -- Hi Alice, I am Bot
print(tostring(g)) -- Greeter(Bot)
-- __call lets a table be invoked like a functionCoroutines
Création de coroutines
coroutine.create crée une coroutine
local Animal = {}
Animal.__index = Animal
function Animal.new(name)
local self = setmetatable({}, Animal)
self.name = name
return self
end
function Animal:speak()
return self.name .. " makes a sound"
end
local a = Animal.new("Cat")
print(a:speak()) -- Cat makes a soundReprise de coroutines
resume démarre ou reprend une coroutine
local Counter = {}
Counter.__index = Counter
function Counter.new()
return setmetatable({count = 0}, Counter)
end
-- the colon ':' adds an implicit 'self' parameter
function Counter:inc()
self.count = self.count + 1
end
local c = Counter.new()
c:inc() -- sugar for Counter.inc(c)
c:inc()
print(c.count) -- 2Statut de coroutine
Les coroutines ont quatre états
local Point = {}
Point.__index = Point
function Point.new(x, y)
local obj = setmetatable({}, Point)
obj.x = x or 0
obj.y = y or 0
return obj
end
function Point:distance(other)
local dx, dy = self.x - other.x, self.y - other.y
return math.sqrt(dx*dx + dy*dy)
end
local p1 = Point.new(0, 0)
local p2 = Point.new(3, 4)
print(p1:distance(p2)) -- 5yield passant des valeurs
yield et resume peuvent passer des valeurs dans les deux sens
local Animal = {}
Animal.__index = Animal
function Animal.new(name) return setmetatable({name = name}, Animal) end
function Animal:speak() return self.name .. " speaks" end
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog
function Dog.new(name)
return setmetatable(Animal.new(name), Dog)
end
function Dog:bark() return self.name .. " barks!" end
local d = Dog.new("Rex")
print(d:speak()) -- Rex speaks (inherited from Animal)
print(d:bark()) -- Rex barks! (Dog's own method)Itérateurs de coroutine
coroutine.wrap renvoie une fonction appelable
local Shape = {}
Shape.__index = Shape
function Shape.new() return setmetatable({}, Shape) end
function Shape:area() return 0 end
local Circle = setmetatable({}, {__index = Shape})
Circle.__index = Circle
function Circle.new(r) return setmetatable({r = r}, Circle) end
function Circle:area() return math.pi * self.r * self.r end -- override
local c = Circle.new(2)
print(c:area()) -- 12.566...
-- call the parent method explicitly: Shape.area(c)Class-based Inheritance Pattern
A small Class() helper standardizes creation and inheritance: new() builds an instance and calls init if present. This pattern is the basis of many Lua OOP libraries (middleclass, classic, etc.).
local function Class(base)
local cls = {}
cls.__index = cls
if base then setmetatable(cls, {__index = base}) end
cls.new = function(...)
local obj = setmetatable({}, cls)
if obj.init then obj:init(...) end
return obj
end
return cls
end
local Vehicle = Class()
function Vehicle:init(wheels) self.wheels = wheels end
function Vehicle:desc() return self.wheels .. " wheels" end
local Bike = Class(Vehicle)
function Bike:init() Vehicle.init(self, 2) end
print(Bike.new():desc()) -- 2 wheelsModules
Définition de modules
Renvoie une table contenant la fonctionnalité du module
local co = coroutine.create(function(a, b)
print("start", a, b)
local c = coroutine.yield(a + b)
print("resumed with", c)
return "done"
end)
-- coroutine.create returns a thread
print(type(co)) -- thread
print(coroutine.status(co)) -- suspendedUtilisation de modules
require charge le module une seule fois
local co = coroutine.create(function()
for i = 1, 3 do
coroutine.yield(i)
end
end)
print(coroutine.resume(co)) -- true 1
print(coroutine.resume(co)) -- true 2
print(coroutine.resume(co)) -- true 3
print(coroutine.resume(co)) -- true (no more values)
print(coroutine.status(co)) -- deadChemin de module
Dans ?.lua, ? est remplacé par le nom du module
-- states: suspended, running, normal, dead
local co = coroutine.create(function()
coroutine.yield()
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co)
print(coroutine.status(co)) -- suspended (yielded)
coroutine.resume(co)
print(coroutine.status(co)) -- dead
-- coroutine.running() returns the current coroutine (nil in main)
print(coroutine.running()) -- nil (main thread)Rechargement
Vider le cache puis require à nouveau
local co = coroutine.create(function(x)
local y = coroutine.yield(x * 2) -- sends x*2, receives y
local z = coroutine.yield(y * 3) -- sends y*3, receives z
return z
end)
print(coroutine.resume(co, 10)) -- true 20 (x=10, yields 20)
print(coroutine.resume(co, 5)) -- true 15 (y=5, yields 15)
print(coroutine.resume(co, 7)) -- true 7 (z=7, returns 7)coroutine.wrap
coroutine.wrap returns a plain function that resumes the coroutine each call—more convenient than create+resume and perfect for iterators. The trade-off: errors raise instead of returning (ok, err), so there's no built-in error flag.
-- wrap returns a function (not a thread); it auto-resumes
-- and propagates errors instead of returning ok
local gen = coroutine.wrap(function()
for i = 1, 5 do
coroutine.yield(i * i)
end
end)
print(gen()) -- 1
print(gen()) -- 4
print(gen()) -- 9
-- ideal for iterator-style use
for v in coroutine.wrap(function()
coroutine.yield("a"); coroutine.yield("b")
end) do
print(v) -- a, then b
break
endGestion des erreurs
Lancer error
error lance une exception
-- file: mymath.lua
local M = {}
function M.square(n) return n * n end
function M.cube(n) return n * n * n end
M.pi = 3.14159
return M
-- a module is just a table returned by the chunkAppel protégé pcall
pcall capture les erreurs
-- require loads the module and caches it in package.loaded
local mymath = require("mymath")
print(mymath.square(5)) -- 25
print(mymath.cube(3)) -- 27
print(mymath.pi) -- 3.14159
-- subsequent requires return the cached table
local m2 = require("mymath")
print(m2 == mymath) -- true
-- dotted names map to paths: a.b.c -> a/b/c.luaxpcall et traceback
xpcall permet de spécifier un gestionnaire d'erreurs
-- package.path controls where require looks for Lua modules
print(package.path)
-- patterns like ./?.lua;./?/init.lua;? is the module name
-- add a custom directory
package.path = "./libs/?.lua;" .. package.path
-- require("foo") then tries ./libs/foo.lua
-- package.cpath is the equivalent for compiled C modules
-- (?.so on Unix, ?.dll on Windows)assert
assert lance quand la condition est fausse
-- require caches in package.loaded; clear it to reload
package.loaded["mymath"] = nil
local mymath = require("mymath") -- re-runs the chunk
-- a hot-reload helper
local function reload(name)
package.loaded[name] = nil
return require(name)
end
-- warning: existing references to the old table
-- are NOT updated after a reloadNiveau d'error
Le deuxième paramètre contrôle la position de l'erreur
-- pattern 1: return a table (most common)
local M = {}
function M.fn() end
return M
-- pattern 2: keep helpers local, export a clean table
local function helper() end
local function main_fn() helper() end
return { main = main_fn }
-- pattern 3: module() (legacy, Lua 5.1) -- deprecated
-- module("foo"); function _M.fn() endManipulation de chaînes
Opérations de base
la bibliothèque string fournit des opérations sur les chaînes
local function divide(a, b)
if b == 0 then
error("division by zero") -- raises an error
end
return a / b
end
-- the level argument controls the reported position
error("msg", 0) -- no position info added
error("msg", 1) -- points to the caller of error (default)
error("msg", 2) -- points to the caller's caller
-- error() can throw non-string objects too
error({code = 42, msg = "x"})Sous-chaînes
L'index commence à 1, supporte les négatifs
local function risky(x)
if x < 0 then error("negative") end
return math.sqrt(x)
end
local ok, result = pcall(risky, -1)
if ok then
print("result:", result)
else
print("error:", result) -- error: negative
end
local ok2, r2 = pcall(risky, 16)
print(ok2, r2) -- true 4Rechercher et remplacer
find renvoie les positions de début et de fin
local function handler(err)
return debug.traceback("Error: " .. tostring(err), 2)
end
local function f() error("boom") end
-- xpcall takes a handler; Lua 5.3+ also accepts arguments
local ok, err = xpcall(f, handler)
print(ok, err) -- false Error: boom\nstack traceback:...
-- xpcall with arguments (Lua 5.3+)
local function risky(x) if x < 0 then error("x") end return x end
local ok2, r2 = xpcall(risky, handler, 9)
print(ok2, r2) -- true 9Formatage
Similaire à printf du C
-- assert(v, msg) raises if v is nil or false
local function load_config(path)
local f = assert(io.open(path, "r")) -- raises if file missing
return f:read("*a")
end
local n = assert(tonumber("42"), "not a number") -- 42
-- assert(nil, "bad input") -- raises: bad input
-- common idiom: assert on results that return nil on failure
local line = assert(f:read("*L"))Caractères et ASCII
char et byte convertissent entre eux
local function check(x)
if type(x) ~= "number" then
-- level 2 blames the caller of check, not check itself
error("expected number, got " .. type(x), 2)
end
return x * 2
end
-- level 0: add no position information
-- level 1: point at the error() call (default)
-- level 2: point at who called the function containing error()Fonctions mathématiques
Mathématiques de base
la bibliothèque math fournit des fonctions mathématiques
-- the simple model uses default input/output streams
io.write("Enter your name: ")
local name = io.read() -- read a line
print("Hi " .. name)
-- io.read modes:
-- "*n" a number
-- "*a" the entire remaining input
-- "*l" a line (default, no newline)
-- "*L" a line including the newline
local n = io.read("*n")
local all = io.read("*a")Fonctions trigonométriques
Les paramètres sont en radians
io.output("out.txt") -- set the default output file
io.write("line one\n")
io.write("line two\n")
io.close() -- close the default output
-- append mode needs io.open
local f = io.open("out.txt", "a")
f:write("appended\n")
f:close()Logarithmes et puissances
Le deuxième paramètre de log est la base
-- io.open returns a file handle (or nil + error message)
local f, err = io.open("data.txt", "r")
if not f then
error("could not open: " .. err)
end
local content = f:read("*a") -- read the entire file
print(content)
f:close() -- always close handles
-- handle methods: f:read, f:write, f:lines, f:seek, f:closeNombres aléatoires
Définir d'abord la graine aléatoire
local f = assert(io.open("data.txt", "r"))
for line in f:lines() do
print(line)
end
f:close() -- f:lines does NOT close the handle
-- io.lines(path) opens, iterates, and closes automatically
for line in io.lines("data.txt") do
print(line)
endArrondi et signe
modf renvoie les parties entière et fractionnaire
-- io.open(path, mode) modes:
-- "r" read (default); file must exist
-- "w" write; truncate or create
-- "a" append; create if missing
-- "r+" read/write; file must exist
-- "w+" read/write; truncate or create
-- "a+" read/append; create if missing
-- append "b" for binary on some systems: "rb", "wb"
local f = io.open("log.txt", "a")
f:write(os.date(), " started\n")
f:close()File Positioning
f:seek moves the read/write position. 'set' is absolute from the start, 'cur' is relative to the current position, 'end' is from the end. seek('end') with no offset returns the file size.
local f = assert(io.open("data.txt", "r"))
-- f:seek(whence, offset)
-- "set": from the start, "cur": from current, "end": from end
print(f:seek("end")) -- file size (position at end)
f:seek("set", 0) -- rewind to the start
local first_line = f:read("*l")
print(first_line)
f:close()Entrées/Sorties fichier
E/S simple
Paramètres du mode io.read
-- Lua patterns are NOT regular expressions; they use % not \
local s = "hello world"
print(s:find("wor")) -- 7 9 (start and end indices)
print(s:find("xyz")) -- nil
-- . matches any single character
print(("abc"):match(".")) -- a
-- string.find / gmatch / gsub / match all use patterns
print(("x = 42"):match("%d+")) -- 42Écriture de fichiers
io.output définit le fichier de sortie
-- %a letters, %d digits, %s whitespace, %w alnum
-- %p punctuation, %l lower, %u upper, %c control
-- uppercase = negation: %A non-letters, %D non-digits
print(("a1 b2"):match("%a%d")) -- a1
print(("x = 42"):match("%d+")) -- 42
-- custom sets: [abc], [a-z], [^0-9]
print(("a-b"):match("[a-z]")) -- a
print(("phone 555-1234"):match("%d+-%d+")) -- 555-1234Descripteurs de fichier
io.open renvoie un descripteur de fichier
-- parentheses () create captures
local s = "name=Alice age=30"
local k, v = s:match("(%w+)=(%w+)")
print(k, v) -- name Alice
-- gmatch iterates over all matches
for key, val in ("a=1 b=2 c=3"):gmatch("(%w+)=(%w+)") do
print(key, val) -- a 1 / b 2 / c 3
end
-- an empty capture () returns the current position
print(("abc"):match("()b")) -- 2Lecture ligne par ligne
f:lines() renvoie un itérateur
local s = "hello world"
print(s:gsub("o", "0")) -- hell0 w0rld 2 (string, count)
-- replacements can reference captures %1, %2
print(("2024-01-15"):gsub("(%d+)-(%d+)-(%d+)", "%3/%2/%1")) -- 15/01/2024 1
-- a function receives captures and returns the replacement
print(("1 2 3"):gsub("%d", function(d) return d * 2 end)) -- 2 4 6 3
-- a 4th argument limits the number of replacements
print(("aaaa"):gsub("a", "b", 2)) -- bbaa 2Modes de fichier
Modes d'ouverture de fichier
-- ^ anchors to the start, $ anchors to the end
print(("hello"):match("^he")) -- he
print(("hello"):match("lo$")) -- lo
print(("hello"):match("^hello$")) -- hello
-- pattern items:
-- * zero or more (greedy)
-- + one or more (greedy)
-- - zero or more (lazy)
-- ? zero or one
print(("aXXXb"):match("a(%a+)b")) -- XXX (greedy)
print(("<!--c-->"):match("<!--(.-)-->")) -- c (lazy)Date/Heure
Heure courante
os.date("*t") renvoie une table
local s = "Lua"
print(s:upper(), s:lower(), s:len()) -- LUA lua 3
print(s:rep(3)) -- LuaLuaLua
print(s:reverse()) -- auL
print(s:sub(1, 2)) -- Lu
print(s:byte(1), string.char(76)) -- 76 L
print(string.format("%s %d", "v", 5)) -- Lua v 5
-- full set: find, gmatch, gsub, match, format,
-- rep, sub, byte, char, len, upper, lower, pack, unpackHeure formatée
Format de type strftime
local t = {1, 2, 3}
table.insert(t, 4) -- {1,2,3,4}
table.insert(t, 1, 0) -- {0,1,2,3,4}
table.remove(t, 1) -- removes 0, returns it
table.sort(t) -- sort in place
print(table.concat(t, ",")) -- 1,2,3,4
-- Lua 5.2+: table.pack / table.unpack
local args = table.pack(1, 2, 3) -- {1,2,3, n=3}
print(table.unpack(args)) -- 1 2 3
-- Lua 5.3+: table.move(src, f, e, t[, dst])Table de temps
Convertir une table de temps en timestamp
print(math.pi, math.huge) -- 3.1415926535898 inf
print(math.max(1, 5, 3)) -- 5
print(math.floor(3.7), math.ceil(3.2)) -- 3 4
print(math.abs(-5)) -- 5
print(math.sqrt(16)) -- 4.0
print(math.sin(math.pi / 2)) -- 1.0 (radians)
print(math.random(1, 100)) -- random int in [1,100]
math.randomseed(os.time()) -- seed the generator
print(math.type(3), math.type(3.0)) -- integer floatDifférence de temps
os.difftime calcule la différence de temps
-- default input/output streams
io.write("to stdout\n")
local line = io.read("*l") -- read a line
-- file handles
local f = io.open("x.txt", "w")
f:write("data\n")
f:close()
-- io.stdin, io.stdout, io.stderr are handles
io.stderr:write("an error\n")
-- io.tmpfile() returns a handle to an auto-deleted temp file
local tmp = io.tmpfile()
tmp:write("scratch")
tmp:seek("set", 0)clock
os.clock renvoie le temps CPU
print(os.time()) -- current timestamp (seconds)
print(os.date("%Y-%m-%d %H:%M")) -- formatted date
local t = os.date("*t") -- table: year, month, day, hour...
print(t.year, t.month, t.day)
print(os.getenv("PATH")) -- an environment variable (or nil)
os.execute("ls") -- run a shell command
local h = io.popen("date") -- capture command output
print(h:read("*a"))
h:close()Debug library
The debug library offers introspection: traceback for stacks, getinfo for function/frame metadata, getlocal/setlocal for variables, and setmetatable/getmetatable that bypass metamethod restrictions. Use sparingly—it can break invariants.
-- debug.traceback returns a call-stack string
local function f() error("x") end
print(xpcall(f, function(e) return debug.traceback(e) end))
-- debug.getinfo returns info about a function or stack frame
local info = debug.getinfo(print)
print(info.what, info.name) -- C print
-- debug.getlocal / setlocal inspect stack locals
local function locals()
local a = 1
local name, value = debug.getlocal(1, 1)
print(name, value) -- a 1
end
locals()Correspondance de motifs
Motifs de base
Les motifs Lua ne sont pas des expressions régulières
// Lua is embedded via a C library; the core object is lua_State
// Headers: lua.h, lauxlib.h, lualib.h
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
int main(void) {
lua_State *L = luaL_newstate(); // create a state
luaL_openlibs(L); // open the standard libs
luaL_dostring(L, "print('hi')"); // run Lua source
lua_close(L); // free the state
return 0;
}Classes de caractères
Classes de caractères des motifs Lua
// all communication with Lua goes through a stack
lua_State *L = luaL_newstate();
// push values
lua_pushinteger(L, 42);
lua_pushstring(L, "hello");
// stack now: bottom[42]["hello"]top
// inspect (1-based from bottom, negative from top)
int top = lua_gettop(L); // 2
lua_Integer n = lua_tointeger(L, 1); // 42
const char *s = lua_tostring(L, 2); // "hello"
lua_pop(L, 2); // pop 2 valuesCaptures
() capture le contenu correspondant
// script.lua: function add(a, b) return a + b end
luaL_dofile(L, "script.lua");
lua_getglobal(L, "add"); // push the function 'add'
lua_pushinteger(L, 3); // arg 1
lua_pushinteger(L, 4); // arg 2
// lua_pcall(L, nargs, nresults, msgh)
if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
fprintf(stderr, "error: %s\n", lua_tostring(L, -1));
} else {
lua_Integer sum = lua_tointeger(L, -1); // 7
lua_pop(L, 1); // pop the result
}Remplacement gsub
Peut utiliser une fonction comme remplacement
// a Lua-callable C function has signature: int fn(lua_State *L)
static int l_square(lua_State *L) {
lua_Integer n = luaL_checkinteger(L, 1); // read arg 1, type-checked
lua_pushinteger(L, n * n); // push the result
return 1; // number of results
}
// register it so Lua can call it
lua_pushcfunction(L, l_square);
lua_setglobal(L, "square");
// now in Lua: print(square(5)) -> 25Ancres
^ pour le début, $ pour la fin
// register a table of C functions as a Lua module
static const luaL_Reg mylib[] = {
{"square", l_square},
{"cube", l_cube},
{NULL, NULL} // sentinel marks the end
};
int luaopen_mylib(lua_State *L) {
luaL_newlib(L, mylib); // create a table and register the funcs
return 1; // return that table (the module)
}
// in Lua: local mylib = require("mylib"); print(mylib.square(5))
// compiled as a shared lib (.so/.dll) found via package.cpathFermetures
Bases des fermetures
Les fermetures capturent les variables externes
-- LuaJIT is a Just-In-Time compiler for Lua 5.1, much faster
-- detect LuaJIT at runtime
if jit then
print(jit.version) -- e.g. LuaJIT 2.1.0-beta3
print(jit.status()) -- true if JIT compilation is on
print(jit.os, jit.arch) -- e.g. Linux x64
end
-- 'jit' is nil on standard PUC Lua, so this guard is safe
if not jit then
print("running plain Lua")
endEncapsulation d'état
Les fermetures implémentent un état privé
jit.on() -- enable JIT compilation globally
jit.off() -- disable it (fall back to the interpreter)
jit.flush() -- flush the compiled-code cache
-- control compilation per-function
local function hot()
local s = 0
for i = 1, 1e6 do s = s + i end
return s
end
jit.off(hot) -- never compile this function
-- jit.on(hot) to re-enable
-- useful for debugging or working around compiler bugsGénérateurs
Les fermetures implémentent le motif de générateur
local ffi = require("ffi")
-- ffi.C is the default C namespace (libc on most systems)
-- ffi.load("name") loads a shared library explicitly
local C = ffi.C
local libc = ffi.load("c")
-- many standard C functions are available right away
print(ffi.C.time(nil)) -- current Unix timestamp
-- ffi.load("m") for libm, ffi.load("ssl") for OpenSSL, etc.FFI: Type Declarations (cdef)
ffi.cdef declares C types, structs, and function prototypes (similar to a header). ffi.new allocates a C object; ffi.C (or a loaded library) calls the declared functions. C structs are usable as Lua values with near-C speed.
local ffi = require("ffi")
-- declare C types and prototypes with ffi.cdef
ffi.cdef[[
typedef struct { int x, y; } Point;
int printf(const char *fmt, ...);
]]
-- create and use a C struct directly
local p = ffi.new("Point", {x = 1, y = 2})
print(p.x, p.y) -- 1 2
ffi.C.printf("p = (%d, %d)\n", p.x, p.y) -- calls libc printfFFI: Calling C Functions
After cdef declares a prototype, ffi.C.name calls the C function. C numbers map to Lua numbers; C strings (char*) must be converted with ffi.string to become Lua strings. Under the JIT these calls have minimal overhead.
local ffi = require("ffi")
ffi.cdef[[
double sqrt(double x);
int abs(int x);
const char *getenv(const char *name);
]]
-- call C's math functions directly (very fast under JIT)
local root = ffi.C.sqrt(16.0) -- 4.0
local pos = ffi.C.abs(-7) -- 7
print(root, pos)
-- ffi.string converts a C string (const char *) to a Lua string
local path = ffi.string(ffi.C.getenv("PATH"))
print(#path)FFI: Callbacks from C to Lua
ffi.cast turns a Lua function into a C function pointer usable as a callback. C arrays are zero-indexed. Callbacks are expensive and must be freed with :free() when no longer needed (they pin Lua objects).
local ffi = require("ffi")
ffi.cdef[[
typedef int (*cmp_fn)(const void *, const void *);
void qsort(void *base, size_t n, size_t sz, cmp_fn cmp);
]]
-- create a C callback that calls back into Lua
local arr = ffi.new("int[?]", 5, {5, 3, 1, 4, 2})
local cmp = ffi.cast("cmp_fn", function(a, b)
return ffi.cast("int*", a)[0] - ffi.cast("int*", b)[0]
end)
ffi.C.qsort(arr, 5, ffi.sizeof("int"), cmp)
for i = 0, 4 do io.write(arr[i], " ") end -- 1 2 3 4 5
cmp:free() -- free the callback when donePortée
Portée locale
do-end crée une portée de bloc
-- Redis runs Lua scripts via EVAL; keys are KEYS, args are ARGV
-- the script returns a single value to Redis
-- run in redis-cli:
-- EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 mykey hello
local key = KEYS[1]
local val = ARGV[1]
redis.call('SET', key, val)
return redis.call('GET', key) -- "hello"
-- redis.call: errors abort the script
-- redis.pcall: errors are returned as a tableCapture par fermeture
Les fermetures détiennent des références de variables
-- KEYS[1..N] = keys passed to EVAL (N is EVAL's 2nd argument)
-- ARGV[1..M] = additional arguments
-- EVAL "..." numkeys key1 key2... arg1 arg2...
-- example: sum the values at multiple keys
local total = 0
for i = 1, #KEYS do
local v = tonumber(redis.call('GET', KEYS[i]))
if v then total = total + v end
end
return total
-- use SCRIPT LOAD + EVALSHA to cache and reuse scriptsVariables de boucle
En Lua, les variables de boucle sont nouvelles à chaque itération
-- OpenResty embeds LuaJIT in Nginx via ngx_http_lua_module
-- content_by_lua_block runs Lua to generate the response
-- nginx.conf:
-- location /hello {
-- content_by_lua_block {
-- ngx.say("hello from lua")
-- }
-- }
-- ngx.say writes to the response body (with a newline)
-- ngx.print writes without a newline
ngx.status = 200
ngx.say("Hello, ", ngx.var.arg_name)upvalue
Les variables externes référencées par les fermetures sont appelées upvalues
-- ngx.var.* accesses Nginx variables
local uri = ngx.var.uri
local ua = ngx.var.http_user_agent
-- ngx.req: the request API
ngx.req.read_body()
local body = ngx.req.get_body_data()
-- request headers (table, case-insensitive keys)
local h = ngx.req.get_headers()
print(h["Content-Type"])
-- set response headers, then write the body
ngx.header["X-Custom"] = "yes"
ngx.say("uri=", uri)ngx.location.capture
ngx.location.capture issues a non-blocking subrequest to another Nginx location and returns status, header, and body. capture_multi runs several in parallel. Subrequests don't go to the client—they're an internal composition tool.
-- issue subrequests to other Nginx locations
local res = ngx.location.capture("/api/users")
if res.status == 200 then
ngx.say(res.body)
end
-- capture_multi: parallel subrequests
local res1, res2 = ngx.location.capture_multi{
{"/api/a"},
{"/api/b"},
}
ngx.say(res1.body, res2.body)
-- subrequests are internal; great for composing upstream servicesShared Dict (ngx.shared)
Shared dicts (lua_shared_dict) are thread-safe, in-memory stores shared across Nginx worker processes. They support atomic ops like incr and add, making them ideal for rate limiting, caching, and locks in OpenResty apps.
-- in nginx.conf: lua_shared_dict cache 10m;
-- access a dict shared across worker processes
local cache = ngx.shared.cache
cache:set("user:1", "Alice", 60) -- key, value, ttl in seconds
local name = cache:get("user:1") -- "Alice"
cache:incr("hits", 1, 0) -- atomic increment, init 0
cache:delete("old")
-- safe for concurrent access across Nginx workers
-- common uses: rate limiting, caching, distributed locks
local locked = cache:add("lock:job", 1, 30) -- set only if absentSnippets Lua associés
Copy-paste ready code for common tasks.
Table (Arrays et Maps)
Table est la seule structure de données de Lua : array et map.
Metatable et OOP
OOP et surcharge d'opérateurs via metatable.
Coroutines
Multitâche coopératif avec les coroutines.
Modules
Créer des modules réutilisables en Lua.
Manipulation de Strings
Pattern matching et fonctions de string en Lua.
E/S de Fichiers
Lire et écrire des fichiers en Lua.
OOP avec Héritage
Implémenter l'héritage de classes avec metatable.
Gestion d'Erreurs (pcall)
Appels protégés et gestion d'erreurs en Lua.
Was this helpful?