Lua — это лёгкий, быстрый и гибкий скриптовый язык, который появился в 1993 году. Он написан на C и чаще всего используется не как самостоятельный язык, а как встраиваемый инструмент для других приложений.
Если вы играли в World of Warcraft и устанавливали аддоны, вы уже сталкивались с Lua. Redis исполняет Lua-скрипты внутри себя. Nginx использует его для обработки HTTP-запросов. В NeoVim плагины тоже можно писать на Lua. Короче говоря — язык не из популярных топов, но крайне полезен и встраиваем во многие инфраструктурные решения.
Синтаксис Lua: просто и понятно
Начнём с классики:
print("Hello, World!")
Синтаксис Lua немного напоминает Pascal и Python: конструкции завершаются end, типы выводятся автоматически, всё просто и компактно — идеально для скриптов и прототипов.
В языке есть локальные и глобальные переменные:
Локальные объявляются через local и живут только в пределах текущего блока.
Глобальные — по умолчанию. Они сохраняются в специальной таблице _G, доступной из любого куска кода, работающего в той же среде выполнения.
Пример чуть более практичный — задача из Advent of Code 2022, день 1:
Найти максимальную сумму чисел, сгруппированных по блокам, разделённым пустыми строками.
local max, current = 0, 0
for line in io.lines("input.txt") do
if line == "" then
if current > max then
max = current
end
current = 0
else
current = current + tonumber(line)
end
end
if current > max then
max = current
end
print(max)
Типы данных в Lua
В Lua всего восемь базовых типов:
number, string, boolean, nil, function, table, thread, userdata
Несколько нюансов:
number
объединяет и целые, и дробные числа.string
— обычные строки, являются иммутабельными.nil
— Null, Nil, None называй как хочешь.function
— функции — это значения первого класса: их можно присваивать переменным, передавать как аргументы и возвращать из других функций.table
— универсальная структура данных: массив (индексируются с 1), словарь и объект — всё в одном.thread
— корутины.userdata
— интерфейс для взаимодействия с C-данными.
Типизация динамическая и слабая: переменные могут менять тип на лету, а Lua часто пытается «угадать» вашу задумку. Например, строку "42"
можно неявно превратить в число. А если все таки хочется явного приведения типов, то существуют встроенные функции для такого: например tonumber(n)
или tostring(s)
.
Встраиваемость: главная сила Lua
Lua удобно встроить в любую программу на C или даже Go. Интерпретатор предоставляет простой C API, через который можно выполнять скрипты, обмениваться данными и расширять язык новыми функциями.
Пример: как исполнить Lua-скрипт из Go
Предположим есть Lua-файл fib5.lua
который считает число Фибоначчи и возвращает результат для числа 5.
function fib(n)
local fib = {1, 1}
for i = 3,n,1 do
fib[#fib+1] = fib[#fib] + fib[#fib-1]
end
return fib[n]
end
return fib(5)
Программа на Go:
Я буду использовать пакет github.com/yuin/gopher-lua который предоставляет простой интерфейс взаимодействия, но при желании можно обойтись и без лишних зависимостей с помощью CGO.
package main
import (
"fmt"
lua "github.com/yuin/gopher-lua"
)
func main() {
var l *lua.LState = lua.NewState()
defer l.Close()
if err := l.DoFile("fib5.lua"); err != nil {
panic(err)
}
// достаем результат выполнения с вершины стэка
result := l.Get(-1) // result типа lua.LValue
// и очищаем его
l.Pop(1)
fmt.Printf("result: %d\n", result) // result: 5
}
Eсли мы захотим заново выполнить подсчет, то нам не надо заново загружать файл, функция fib(n)
уже лежит в глобальных переменных нашего l *lua.LState
Нужно лишь достать её оттуда и положить на стэк вместе с аргументами, а затем вызвать l.Call(nargs, nret)
для получения результата.
...
//складываем на стэк функцию из глобальных переменных
l.Push(l.GetGlobal("fib")) // stack: function "fib"
//складываем на стэк аргумент функции
l.Push(lua.LNumber(15)) // stack: function "fib", 15
// l.Call забирает из стэка функцию и 1 аргумент, и складывает обратно 1 результат
l.Call(1, 1) // stack: 610
result = l.Get(-1) // stack: 610
l.Pop(1) // stack:
fmt.Printf("result: %d\n", result) //result: 610
Небольшое уточнение: не примитивные типы используемые в 2 языках сильно отличаются (особенно массивы), поэтому часто требуется нетривиальные преобразования чтобы получить нормальный результат.
Где Lua уже используется
Lua активно применяется в реальных проектах:
World of Warcraft — аддоны и интерфейс.
Redis — атомарные операции в скриптах.
Nginx — модуль ngx_http_lua_module.
NeoVim — современный API для плагинов.
Игровые движки — Defold, Pico-8, Love2D и другие.
Зачем учить Lua в 2025 году?
Lua — не универсальный язык на все случаи жизни. Но если вы:
пишете backend на Nginx или Redis,
работаете с NeoVim и хотите делать плагины,
или просто хотите встроить скриптовый язык в своё приложение,
... то Lua — это идеальный инструмент. Он маленький, быстрый и гибкий. И к тому же — приятно удивляет своей лаконичностью.