LEARN X · ЗА 13 МИН
Lua
Экспресс-тур по Lua: весь язык на одной странице в комментариях кода — таблицы, метатаблицы, ООП, замыкания, корутины и стандартная библиотека.
Lua — маленький, быстрый и встраиваемый язык: игры (Roblox, World of Warcraft), конфиги (Nginx, Redis), скрипты. Минимум синтаксиса, одна структура данных — таблица. Здесь весь язык за 13 минут, прямо в комментариях кода.
1. Вывод и комментарии
-- Однострочный комментарий начинается с двух дефисов
--[[
Многострочный комментарий
занимает несколько строк
]]
print("Привет, Lua!") -- Привет, Lua!
print(1, 2, 3) -- 1 2 3 (аргументы через табуляцию)
io.write("без переноса") -- печатает без \n в конце
2. Переменные и типы
Типизация динамическая: тип у значения, а не у переменной.
-- local делает переменную локальной (всегда так и делайте!)
local x = 10 -- без local переменная глобальная
local name = "Аня"
-- nil — отсутствие значения (как null)
local nothing = nil
print(nothing) -- nil
-- boolean: только nil и false ложны, ВСЁ остальное истинно (даже 0 и "")
local flag = true
-- number — одно числовое: и целые, и дробные (в Lua 5.3+ есть подтипы)
local n = 42
local pi = 3.14
local hex = 0xFF -- 255
-- string — строки
local s = "текст"
-- type() возвращает имя типа строкой
print(type(x)) -- number
print(type(name)) -- string
print(type(nil)) -- nil
print(type(true)) -- boolean
print(type(print)) -- function
-- Множественное присваивание
local a, b, c = 1, 2, 3
a, b = b, a -- обмен значениями без temp
3. Строки
-- Конкатенация — оператор .. (точка-точка), НЕ +
local hello = "При" .. "вет" -- "Привет"
local mix = "Год: " .. 2026 -- число само превратится в строку
-- Многострочные строки в двойных квадратных скобках
local text = [[
Первая строка
Вторая строка
]]
-- Длина строки — оператор #
print(#"Lua") -- 3
-- Методы из библиотеки string
print(string.upper("lua")) -- LUA
print(string.lower("LUA")) -- lua
print(string.len("Lua")) -- 3
print(string.sub("Привет", 1, 3)) -- первые символы (байты!)
print(string.rep("ab", 3)) -- ababab
print(string.format("%d + %d = %d", 2, 2, 4)) -- 2 + 2 = 4
-- Можно вызывать методы прямо на строке через двоеточие
print(("lua"):upper()) -- LUA
-- Поиск и замена (шаблоны Lua, не regex)
print(string.find("hello", "ll")) -- 3 4
print(string.gsub("hello", "l", "L")) -- heLLo 2 (строка и число замен)
4. Операторы и условия
-- Арифметика
print(7 + 2) -- 9
print(7 - 2) -- 5
print(7 * 2) -- 14
print(7 / 2) -- 3.5 (деление всегда даёт дробь)
print(7 % 2) -- 1 (остаток)
print(7 // 2) -- 3 (целочисленное деление, Lua 5.3+)
print(2 ^ 10) -- 1024 (возведение в степень)
-- Сравнение: равно ==, НЕ равно ~= (тильда-равно, не !=)
print(1 == 1) -- true
print(1 ~= 2) -- true
print(3 < 5) -- true
print(5 >= 5) -- true
-- Логические: and, or, not (слова, не && ||)
print(true and false) -- false
print(true or false) -- true
print(not true) -- false
-- and/or возвращают операнд, а не строго boolean — удобно для значений по умолчанию
local name = nil
local display = name or "Гость" -- "Гость"
print(display)
-- Условие: if / elseif / else / end
local n = 7
if n > 10 then
print("много")
elseif n > 5 then
print("средне") -- сработает это
else
print("мало")
end
5. Циклы
-- while — проверка ДО тела
local i = 1
while i <= 3 do
print(i) -- 1, 2, 3
i = i + 1 -- нет ++ и += в базовом Lua
end
-- repeat / until — проверка ПОСЛЕ тела (выполнится минимум раз)
local j = 1
repeat
print(j)
j = j + 1
until j > 3 -- 1, 2, 3
-- numeric for: от, до (включительно), шаг (по умолчанию 1)
for k = 1, 5 do print(k) end -- 1..5
for k = 10, 1, -2 do print(k) end -- 10, 8, 6, 4, 2
-- generic for с ipairs — по массиву (индексы 1, 2, 3... до первого nil)
local fruits = {"яблоко", "груша", "слива"}
for index, value in ipairs(fruits) do
print(index, value) -- 1 яблоко / 2 груша / 3 слива
end
-- generic for с pairs — по всем ключам таблицы (порядок не гарантирован)
local person = {name = "Аня", age = 30}
for key, value in pairs(person) do
print(key, value) -- name Аня / age 30 (порядок любой)
end
-- break прерывает цикл; continue в Lua НЕТ (используют goto или вложенный if)
6. Таблицы
Таблица — единственная структура данных в Lua. Это и массив, и словарь, и объект.
-- Как массив (индексация с 1, а не с 0!)
local arr = {"a", "b", "c"}
print(arr[1]) -- a (первый элемент — индекс 1)
print(arr[3]) -- c
print(#arr) -- 3 (# — длина массива)
arr[4] = "d" -- добавили четвёртый
-- Как словарь (ключ-значение)
local user = {
name = "Иван",
age = 25,
["любимый цвет"] = "синий", -- ключ с пробелом — в скобках
}
print(user.name) -- Иван (точечный доступ)
print(user["age"]) -- 25 (доступ по строке-ключу)
user.email = "[email protected]" -- добавили поле
user.age = nil -- удалили поле (присвоили nil)
-- Смешанная таблица — и массив, и словарь сразу
local mixed = {10, 20, 30, type = "числа"}
print(mixed[1]) -- 10
print(mixed.type) -- числа
-- Вложенные таблицы
local data = {
users = {
{name = "A"},
{name = "B"},
},
}
print(data.users[2].name) -- B
7. Функции
-- Объявление
function greet(name)
return "Привет, " .. name
end
print(greet("Lua")) -- Привет, Lua
-- Функция — значение, её можно положить в переменную
local square = function(x) return x * x end
print(square(5)) -- 25
-- Множественный возврат
function minmax(a, b)
if a < b then return a, b else return b, a end
end
local lo, hi = minmax(8, 3)
print(lo, hi) -- 3 8
-- Переменное число аргументов (variadic) через ...
function sum(...)
local total = 0
for _, v in ipairs({...}) do -- ... упаковываем в таблицу
total = total + v
end
return total
end
print(sum(1, 2, 3, 4)) -- 10
-- Замыкания: внутренняя функция помнит локальные переменные внешней
function counter()
local count = 0
return function()
count = count + 1 -- count живёт между вызовами
return count
end
end
local next = counter()
print(next()) -- 1
print(next()) -- 2
print(next()) -- 3
8. Таблицы как объекты
Двоеточие : — это сахар: оно неявно передаёт таблицу первым аргументом self.
local account = {balance = 100}
-- Метод через двоеточие: внутри доступен self (сама таблица)
function account:deposit(amount)
self.balance = self.balance + amount
end
-- Вызов тоже через двоеточие
account:deposit(50)
print(account.balance) -- 150
-- account:deposit(50) — это сахар для account.deposit(account, 50)
-- Двоеточие при объявлении и вызове просто прячет первый аргумент self
function account.withdraw(self, amount) -- эквивалент с точкой
self.balance = self.balance - amount
end
account:withdraw(30)
print(account.balance) -- 120
9. Метатаблицы и ООП
У таблиц нет встроенных классов. ООП собирают вручную из метатаблиц и поля __index.
-- Метатаблица меняет поведение таблицы через метаметоды (__index, __add, ...)
local Animal = {}
Animal.__index = Animal -- ищем недостающие поля в самом Animal
-- "Конструктор"
function Animal.new(name, sound)
local self = setmetatable({}, Animal) -- привязываем метатаблицу
self.name = name
self.sound = sound
return self
end
function Animal:speak()
return self.name .. " говорит " .. self.sound
end
local cat = Animal.new("Кот", "мяу")
print(cat:speak()) -- Кот говорит мяу
-- Наследование: метатаблица потомка ссылается на родителя
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog
function Dog.new(name)
local self = Animal.new(name, "гав") -- зовём родительский конструктор
return setmetatable(self, Dog)
end
function Dog:fetch() -- свой метод
return self.name .. " принёс мячик"
end
local d = Dog.new("Рекс")
print(d:speak()) -- Рекс говорит гав (унаследовано от Animal)
print(d:fetch()) -- Рекс принёс мячик
-- Перегрузка операторов через метаметоды
local Vec = {}
Vec.__index = Vec
Vec.__add = function(a, b) -- что делает оператор + для Vec
return setmetatable({x = a.x + b.x, y = a.y + b.y}, Vec)
end
local v = setmetatable({x = 1, y = 2}, Vec) + setmetatable({x = 3, y = 4}, Vec)
print(v.x, v.y) -- 4 6
10. Стандартная библиотека
-- table — работа с таблицами-массивами
local t = {"a", "b", "c"}
table.insert(t, "d") -- добавить в конец: {a,b,c,d}
table.insert(t, 1, "z") -- вставить по индексу: {z,a,b,c,d}
table.remove(t, 1) -- удалить по индексу (вернёт удалённое)
table.remove(t) -- удалить последний
print(table.concat({"a","b","c"}, "-")) -- a-b-c (склейка в строку)
local nums = {3, 1, 2}
table.sort(nums) -- сортировка на месте: {1, 2, 3}
print(nums[1]) -- 1
-- math — математика
print(math.floor(3.7)) -- 3
print(math.ceil(3.2)) -- 4
print(math.abs(-5)) -- 5
print(math.max(1, 9, 4)) -- 9
print(math.min(1, 9, 4)) -- 1
print(math.sqrt(16)) -- 4.0
print(math.pi) -- 3.1415926535898
math.randomseed(os.time())
print(math.random(1, 6)) -- случайное от 1 до 6
-- string — уже видели: format, sub, gsub, find, upper, lower, rep, len
-- os — операционная система (кратко)
print(os.time()) -- метка времени (секунды с эпохи)
print(os.date("%Y-%m-%d")) -- текущая дата, напр. 2026-06-16
print(os.clock()) -- процессорное время (для замеров)
11. Обработка ошибок
-- error() выбрасывает ошибку
local function divide(a, b)
if b == 0 then
error("деление на ноль")
end
return a / b
end
-- pcall (protected call) ловит ошибку и не роняет программу
-- Возвращает: успех (boolean) + результат ИЛИ текст ошибки
local ok, result = pcall(divide, 10, 2)
print(ok, result) -- true 5.0
local ok2, err = pcall(divide, 10, 0)
print(ok2, err) -- false деление на ноль (с префиксом файла/строки)
-- Типичный паттерн обработки
if ok2 then
print("Результат: " .. err)
else
print("Ошибка: " .. err) -- Ошибка: ...деление на ноль
end
-- xpcall добавляет обработчик-трейсбек
local ok3 = xpcall(function()
error("что-то сломалось")
end, function(e)
return "перехвачено: " .. e
end)
print(ok3) -- false