Skip to content

Lua Шпаргалка

Lua — мощный, быстрый, лёгкий, встраиваемый скриптовый язык.

01

Основы

Hello World

print автоматически добавляет перенос строки

lua
-- 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  3

Комментарии

--[[ ]] для многострочных комментариев

lua
-- 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")

Необязательные точки с запятой

Точки с запятой опциональны

lua
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")

Множественное присваивание

Поддерживает одновременное присваивание нескольким переменным

lua
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  2

Интерактивный режим

lua -i входит в интерактивный режим

lua
-- 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)
-- ababab

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

lua
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 = nil
02

Переменные

Локальные переменные local

local объявляет локальные переменные

lua
-- 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))) -- string

Глобальные переменные

Без local — глобальная переменная

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

Множественное присваивание

Недостающие значения становятся nil, лишние отбрасываются

lua
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

Обмен значений переменных

Временная переменная не нужна

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

Удаление переменных

Присваивание nil позволяет GC освободить память

lua
-- 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)        -- 3

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

lua
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))     -- nothing
03

Типы данных

Базовые типы

В Lua 8 базовых типов

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

Числа

Lua 5.3+ различает целые и числа с плавающей точкой

lua
-- 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)    -- -2

Строки

# возвращает длину строки

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

Логические значения

0 и пустая строка считаются истинными

lua
-- 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"

Таблицы

table — единственная составная структура данных

lua
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))    -- ababab

Length 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+).

lua
-- # 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)
04

Операторы

Арифметические операторы

^ — возведение в степень, не XOR

lua
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 optional

Целочисленное деление

// — деление с округлением вниз

lua
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
end

Операторы сравнения

~= означает «не равно»

lua
-- 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 == 7

Логические операторы

and/or поддерживают сокращённое вычисление

lua
-- 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 here

Конкатенация строк

.. объединяет строки

lua
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)
end

Оператор длины

# возвращает длину строки или таблицы

lua
-- 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 scope
05

Управление потоком

if-elseif-else

Обратите внимание на ключевые слова then и end

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

Цикл while

while-do-end

lua
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

Как do-while, выходит при истинном условии

lua
-- [[ ]] 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

for start, stop, step

lua
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

ipairs итерирует массивы, pairs итерирует всё

lua
-- 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 10

break

В Lua нет continue

lua
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)
06

Функции

Определение функции

local function определяет локальную функцию

lua
-- 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)          -- 4

Множественные возвращаемые значения

Функции могут возвращать несколько значений

lua
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"] = 99

Вариативные функции

... представляет вариативные аргументы

lua
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 1

Анонимные функции

Функции — объекты первого класса

lua
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 30

Функции как аргументы

Функции высшего порядка

lua
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]) end

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

lua
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}, ""))         -- 123
07

Таблицы

Создание таблиц

Таблицы могут использоваться как массивы и словари

lua
-- 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))      -- 30

Доступ к элементам

Два способа доступа: . и []

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

Операции с массивами

библиотека table предоставляет операции с массивами

lua
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
end

Сортировка

Поддерживается пользовательская функция сравнения

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

Итерация

ipairs итерирует часть-массив

lua
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
end

Длина таблицы

# работает только для смежных массивов

lua
-- 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  30
08

Метатаблицы

Установка метатаблицы

__index определяет поведение поиска

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

Перегрузка операторов

Можно перегружать операторы + - * / == <

lua
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 it

Наследование через __index

Наследование через __index

lua
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 перехватывает присваивания

lua
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 позволяет вызывать таблицу как функцию

lua
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 scope
09

ООП

Имитация классов

Имитация классов через таблицы и метатаблицы

lua
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))   -- MyTable

Создание объектов

Вызов : автоматически передаёт self

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

Наследование

Наследование через цепочку метатаблиц

lua
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 metamethods

Переопределение методов

Метод подкласса переопределяет родительский

lua
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  6

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

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

lua
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 function
10

Сопрограммы

Создание сопрограмм

coroutine.create создаёт сопрограмму

lua
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 sound

Возобновление сопрограмм

resume запускает или возобновляет сопрограмму

lua
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)    -- 2

Статус сопрограммы

Сопрограммы имеют четыре состояния

lua
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))   -- 5

Передача значений через yield

yield и resume могут передавать значения в обе стороны

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

Итераторы сопрограмм

coroutine.wrap возвращает вызываемую функцию

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

lua
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 wheels
11

Модули

Определение модулей

Возвращает таблицу с функциональностью модуля

lua
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))  -- suspended

Использование модулей

require загружает модуль только один раз

lua
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))  -- dead

Путь к модулю

В ?.lua ? заменяется именем модуля

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

Перезагрузка

Очистите кэш, затем require снова

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

lua
-- 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
end
12

Обработка ошибок

Выброс error

error выбрасывает исключение

lua
-- 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 chunk

Защищённый вызов pcall

pcall отлавливает ошибки

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

xpcall и traceback

xpcall позволяет задать обработчик ошибок

lua
-- 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 выбрасывает при ложном условии

lua
-- 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 reload

Уровень ошибки

Второй параметр управляет позицией ошибки

lua
-- 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() end
13

Манипуляции со строками

Базовые операции

библиотека string предоставляет строковые операции

lua
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"})

Подстроки

Индексация с 1, поддерживает отрицательные

lua
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  4

Поиск и замена

find возвращает начальную и конечную позиции

lua
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  9

Форматирование

Аналогично C printf

lua
-- 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"))

Символы и ASCII

char и byte преобразуют друг в друга

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

Математические функции

Базовая математика

библиотека math предоставляет математические функции

lua
-- 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")

Тригонометрические функции

Параметры в радианах

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

Логарифмы и степени

Второй параметр log — основание

lua
-- 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:close

Случайные числа

Сначала задайте случайное зерно

lua
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)
end

Округление и знак

modf возвращает целую и дробную части

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

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

Файловый ввод-вывод

Простой ввод-вывод

Параметры режима io.read

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

Запись файлов

io.output устанавливает файл вывода

lua
-- %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-1234

Дескрипторы файлов

io.open возвращает дескриптор файла

lua
-- 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"))   -- 2

Построчное чтение

f:lines() возвращает итератор

lua
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  2

Режимы файлов

Режимы открытия файлов

lua
-- ^ 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)
16

Дата/Время

Текущее время

os.date("*t") возвращает таблицу

lua
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, unpack

Форматированное время

strftime-подобный формат

lua
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])

Таблица времени

Преобразование таблицы времени в timestamp

lua
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  float

Разница времени

os.difftime вычисляет разницу во времени

lua
-- 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 возвращает процессорное время

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

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

Сопоставление шаблонов

Базовые шаблоны

Шаблоны Lua не являются регулярными выражениями

lua
// 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;
}

Классы символов

Классы символов шаблонов Lua

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 values

Захваты

() захватывает совпавшее содержимое

lua
// 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
}

Замена gsub

Можно использовать функцию в качестве замены

lua
// 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))  ->  25

Якоря

^ для начала, $ для конца

lua
// 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.cpath
18

Замыкания

Основы замыканий

Замыкания захватывают внешние переменные

lua
-- 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")
end

Инкапсуляция состояния

Замыкания реализуют приватное состояние

lua
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 bugs

Генераторы

Замыкания реализуют паттерн генератора

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

lua
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 printf

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

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

lua
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 done
19

Область видимости

Локальная область

do-end создаёт блочную область видимости

lua
-- 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 table

Захват замыканием

Замыкания удерживают ссылки на переменные

lua
-- 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 scripts

Переменные цикла

В Lua переменные цикла создаются заново каждую итерацию

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

Внешние переменные, на которые ссылаются замыкания, называются upvalue

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

lua
-- 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 services

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

lua
-- 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 absent

Was this helpful?