Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

Сборник примеров на Lua

Ниже представлены примеры Lua-программ для часто встречающихся или сложных случаев.

Любую из этих программ можно выполнить, скопировав код в .lua-файл, а затем выполнив в командной строке chmod +x ./{имя-программы}.lua и ./{program-name}.lua.

Первая строка — это шебанг:

#!/usr/bin/env tarantool

Он запускает сервер приложений Tarantool на языке Lua, который должен быть в пути выполнения.

Все примеры в данном сборнике можно использовать без ограничений.

Другие примеры см. на GitHub Tarantool.

hello_world.lua

Стандартный пример простой программы.

#!/usr/bin/env tarantoolprint('Hello, World!')

console_start.lua

Для инициализации базы данных (создания спейсов) используйте box.once(), если сервер запускается впервые. Затем используйте console.start(), чтобы запустить интерактивный режим.

#!/usr/bin/env tarantool-- Configure databasebox.cfg {    listen = 3313}box.once("bootstrap", function()    box.schema.space.create('tweedledum')    box.space.tweedledum:create_index('primary',        { type = 'TREE', parts = {1, 'unsigned'}})end)require('console').start()

fio_read.lua

Используйте модуль fio, чтобы открыть, прочитать и закрыть файл.

#!/usr/bin/env tarantoollocal fio = require('fio')local errno = require('errno')local f = fio.open('/tmp/xxxx.txt', {'O_RDONLY' })if not f then    error("Failed to open file: "..errno.strerror())endlocal data = f:read(4096)f:close()print(data)

fio_write.lua

Используйте модуль fio, чтобы открыть, записать данные и закрыть файл.

#!/usr/bin/env tarantoollocal fio = require('fio')local errno = require('errno')local f = fio.open('/tmp/xxxx.txt', {'O_CREAT', 'O_WRONLY', 'O_APPEND'},    tonumber('0666', 8))if not f then    error("Failed to open file: "..errno.strerror())endf:write("Hello\n");f:close()

ffi_printf.lua

Используйте Библиотеку LuaJIT FFI, чтобы вызвать встроенную в C функцию: printf(). (Подробнее про FFI см. Учебное пособие по FFI.)

#!/usr/bin/env tarantoollocal ffi = require('ffi')ffi.cdef[[    int printf(const char *format, ...);]]ffi.C.printf("Hello, %s\n", os.getenv("USER"));

ffi_gettimeofday.lua

Используйте Библиотеку LuaJIT FFI, чтобы вызвать встроенную в C функцию: gettimeofday(). Она позволяет получить значение времени с точностью в миллисекундах, в отличие от функции времени в модуле clock в Tarantool.

#!/usr/bin/env tarantoollocal ffi = require('ffi')ffi.cdef[[    typedef long time_t;    typedef struct timeval {    time_t tv_sec;    time_t tv_usec;} timeval;    int gettimeofday(struct timeval *t, void *tzp);]]local timeval_buf = ffi.new("timeval")local now = function()    ffi.C.gettimeofday(timeval_buf, nil)    return tonumber(timeval_buf.tv_sec * 1000 + (timeval_buf.tv_usec / 1000))end

ffi_zlib.lua

Используйте Библиотеку LuaJIT FFI, чтобы вызвать библиотечную функцию в C. (Подробнее про FFI см. Учебное пособие по FFI.)

#!/usr/bin/env tarantoollocal ffi = require("ffi")ffi.cdef[[    unsigned long compressBound(unsigned long sourceLen);    int compress2(uint8_t *dest, unsigned long *destLen,    const uint8_t *source, unsigned long sourceLen, int level);    int uncompress(uint8_t *dest, unsigned long *destLen,    const uint8_t *source, unsigned long sourceLen);]]local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")-- Lua wrapper for compress2()local function compress(txt)    local n = zlib.compressBound(#txt)    local buf = ffi.new("uint8_t[?]", n)    local buflen = ffi.new("unsigned long[1]", n)    local res = zlib.compress2(buf, buflen, txt, #txt, 9)    assert(res == 0)    return ffi.string(buf, buflen[0])end-- Lua wrapper for uncompresslocal function uncompress(comp, n)    local buf = ffi.new("uint8_t[?]", n)    local buflen = ffi.new("unsigned long[1]", n)    local res = zlib.uncompress(buf, buflen, comp, #comp)    assert(res == 0)    return ffi.string(buf, buflen[0])end-- Simple test code.local txt = string.rep("abcd", 1000)print("Uncompressed size: ", #txt)local c = compress(txt)print("Compressed size: ", #c)local txt2 = uncompress(c, #txt)assert(txt2 == txt)

ffi_meta.lua

Используйте Библиотеку LuaJIT FFI, чтобы получить доступ к объекту в C с помощью метаметода (метод, который определен метатаблицей).

#!/usr/bin/env tarantoollocal ffi = require("ffi")ffi.cdef[[typedef struct { double x, y; } point_t;]]local pointlocal mt = {  __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,  __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,  __index = {    area = function(a) return a.x*a.x + a.y*a.y end,  },}point = ffi.metatype("point_t", mt)local a = point(3, 4)print(a.x, a.y)  --> 3  4print(#a)        --> 5print(a:area())  --> 25local b = a + point(0.5, 8)print(#b)        --> 12.5

print_arrays.lua

Используйте, чтобы создать Lua-таблицы и вывести их на экран. Следует отметить, что для таблицы типа массива (array) функция-итератор будет ipairs(), а для таблицы типа ассоциативного массива (map) функция-итератор – pairs(). (ipairs() быстрее, чем pairs(), но pairs() рекомендуется для ассоциативных массивов или смешанных таблиц.) Результат будет выглядеть следующим образом: "1 Apple \| 2 Orange \| 3 Grapefruit \| 4 Banana \| k3 v3 \| k1 v1 \| k2 v2".

#!/usr/bin/env tarantoolarray = { 'Apple', 'Orange', 'Grapefruit', 'Banana'}for k, v in ipairs(array) do print(k, v) endmap = { k1 = 'v1', k2 = 'v2', k3 = 'v3' }for k, v in pairs(map) do print(k, v) end

count_array.lua

Используйте оператор #, чтобы получить количество элементов в Lua-таблице типа массива. У этой операции сложность O(log(N)).

#!/usr/bin/env tarantoolarray = { 1, 2, 3}print(#array)

count_array_with_nils.lua

Отсутствующие элементы в массивах, которые Lua рассматривает как nil, заставляют простой оператор '#' выдавать неправильные результаты. Команда "print(#t)" выведет "4", команда "print(counter)" выведет "3", а команда "print(max)" – "10". Другие табличные функции, такие как table.sort(), также сработают неправильно при наличии нулевых значений nil.

#!/usr/bin/env tarantoollocal t = {}t[1] = 1t[4] = 4t[10] = 10print(#t)local counter = 0for k,v in pairs(t) do counter = counter + 1 endprint(counter)local max = 0for k,v in pairs(t) do if k > max then max = k end endprint(max)

count_array_with_nulls.lua

Используйте явные значения NULL, чтобы избежать проблем, вызванных тем, что nil в Lua == поведение с пропущенными значениями. Хотя json.NULL == nil является true, все команды вывода в данной программе выведут правильное значение: 10.

#!/usr/bin/env tarantoollocal json = require('json')local t = {}t[1] = 1; t[2] = json.NULL; t[3]= json.NULL;t[4] = 4; t[5] = json.NULL; t[6]= json.NULL;t[6] = 4; t[7] = json.NULL; t[8]= json.NULL;t[9] = json.NULLt[10] = 10print(#t)local counter = 0for k,v in pairs(t) do counter = counter + 1 endprint(counter)local max = 0for k,v in pairs(t) do if k > max then max = k end endprint(max)

count_map.lua

Программа используется для получения количества элементов в таблице типа ассоциативного массива.

#!/usr/bin/env tarantoollocal map = { a = 10, b = 15, c = 20 }local size = 0for _ in pairs(map) do size = size + 1; endprint(size)

swap.lua

Программа использует особенность Lua менять местами две переменные без необходимости использования третьей переменной.

#!/usr/bin/env tarantoollocal x = 1local y = 2x, y = y, xprint(x, y)

class.lua

Используется для создания класса, метатаблицы для класса, экземпляра класса. Другой пример можно найти в http://lua-users.org/wiki/LuaClassesWithMetatable.

#!/usr/bin/env tarantool-- define class objectslocal myclass_somemethod = function(self)    print('test 1', self.data)endlocal myclass_someothermethod = function(self)    print('test 2', self.data)endlocal myclass_tostring = function(self)    return 'MyClass <'..self.data..'>'endlocal myclass_mt = {    __tostring = myclass_tostring;    __index = {        somemethod = myclass_somemethod;        someothermethod = myclass_someothermethod;    }}-- create a new object of myclasslocal object = setmetatable({ data = 'data'}, myclass_mt)print(object:somemethod())print(object.data)

garbage.lua

Запустите сборщик мусора в Lua с помощью функции collectgarbage.

#!/usr/bin/env tarantoolcollectgarbage('collect')

fiber_producer_and_consumer.lua

Запустите один файбер для производителя и один файбер для потребителя. Используйте fiber.channel() для обмена данными и синхронизации. Можно настроить ширину канала (ch_size в программном коде) для управления количеством одновременных задач к обработке.

#!/usr/bin/env tarantoollocal fiber = require('fiber')local function consumer_loop(ch, i)    -- initialize consumer synchronously or raise an error()    fiber.sleep(0) -- allow fiber.create() to continue    while true do        local data = ch:get()        if data == nil then            break        end        print('consumed', i, data)        fiber.sleep(math.random()) -- simulate some work    endendlocal function producer_loop(ch, i)    -- initialize consumer synchronously or raise an error()    fiber.sleep(0) -- allow fiber.create() to continue    while true do        local data = math.random()        ch:put(data)        print('produced', i, data)    endendlocal function start()    local consumer_n = 5    local producer_n = 3    -- Create a channel    local ch_size = math.max(consumer_n, producer_n)    local ch = fiber.channel(ch_size)    -- Start consumers    for i=1, consumer_n,1 do        fiber.create(consumer_loop, ch, i)    end    -- Start producers    for i=1, producer_n,1 do        fiber.create(producer_loop, ch, i)    endendstart()print('started')

socket_tcpconnect.lua

Используйте socket.tcp_connect() для подключения к удаленному серверу по TCP. Можно отобразить информацию о подключении и результат запроса GET.

#!/usr/bin/env tarantoollocal s = require('socket').tcp_connect('google.com', 80)print(s:peer().host)print(s:peer().family)print(s:peer().type)print(s:peer().protocol)print(s:peer().port)print(s:write("GET / HTTP/1.0\r\n\r\n"))print(s:read('\r\n'))print(s:read('\r\n'))

socket_tcp_echo.lua

Используйте socket.tcp_connect() для настройки простого TCP-сервера путем создания функции, которая обрабатывает запросы и отражает их, а затем передачи функции на socket.tcp_server(). Данная программа была протестирована на 100 000 клиентов, каждый из которых получил отдельный файбер.

#!/usr/bin/env tarantoollocal function handler(s, peer)    s:write("Welcome to test server, " .. peer.host .."\n")    while true do        local line = s:read('\n')        if line == nil then            break -- error or eof        end        if not s:write("pong: "..line) then            break -- error or eof        end    endendlocal server, addr = require('socket').tcp_server('localhost', 3311, handler)

getaddrinfo.lua

Используйте socket.getaddrinfo(), чтобы провести неблокирующее разрешение имен DNS, получая как AF_INET6, так и AF_INET информацию для 'google.com'. Данная техника не всегда необходима для TCP-соединений, поскольку socket.tcp_connect() выполняет socket.getaddrinfo с точки зрения внутреннего устройства до попытки соединения с первым доступным адресом.

#!/usr/bin/env tarantoollocal s = require('socket').getaddrinfo('google.com', 'http', { type = 'SOCK_STREAM' })print('host=',s[1].host)print('family=',s[1].family)print('type=',s[1].type)print('protocol=',s[1].protocol)print('port=',s[1].port)print('host=',s[2].host)print('family=',s[2].family)print('type=',s[2].type)print('protocol=',s[2].protocol)print('port=',s[2].port)

socket_udp_echo.lua

В данный момент в Tarantool нет функции udp_server, поэтому socket_udp_echo.lua – более сложная программа, чем socket_tcp_echo.lua. Ее можно реализовать с помощью сокетов и файберов.

#!/usr/bin/env tarantoollocal socket = require('socket')local errno = require('errno')local fiber = require('fiber')local function udp_server_loop(s, handler)    fiber.name("udp_server")    while true do        -- try to read a datagram first        local msg, peer = s:recvfrom()        if msg == "" then            -- socket was closed via s:close()            break        elseif msg ~= nil then            -- got a new datagram            handler(s, peer, msg)        else            if s:errno() == errno.EAGAIN or s:errno() == errno.EINTR then                -- socket is not ready                s:readable() -- yield, epoll will wake us when new data arrives            else                -- socket error                local msg = s:error()                s:close() -- save resources and don't wait GC                error("Socket error: " .. msg)            end        end    endendlocal function udp_server(host, port, handler)    local s = socket('AF_INET', 'SOCK_DGRAM', 0)    if not s then        return nil -- check errno:strerror()    end    if not s:bind(host, port) then        local e = s:errno() -- save errno        s:close()        errno(e) -- restore errno        return nil -- check errno:strerror()    end    fiber.create(udp_server_loop, s, handler) -- start a new background fiber    return send

Функция для клиента, который подключается к этому серверу, может выглядеть следующим образом:

local function handler(s, peer, msg)    -- You don't have to wait until socket is ready to send UDP    -- s:writable()    s:sendto(peer.host, peer.port, "Pong: " .. msg)endlocal server = udp_server('127.0.0.1', 3548, handler)if not server then    error('Failed to bind: ' .. errno.strerror())endprint('Started')require('console').start()

http_get.lua

Используйте модуль http для получения данных по HTTP.

#!/usr/bin/env tarantoollocal http_client = require('http.client')local json = require('json')local r = http_client.get('https://api.frankfurter.app/latest?to=USD%2CRUB')if r.status ~= 200 then    print('Failed to get currency ', r.reason)    returnendlocal data = json.decode(r.body)print(data.base, 'rate of', data.date, 'is', data.rates.RUB, 'RUB or', data.rates.USD, 'USD')

http_send.lua

Используйте модуль http для отправки данных по HTTP.

#!/usr/bin/env tarantoollocal http_client = require('http.client')local json = require('json')local data = json.encode({ Key = 'Value'})local headers = { Token = 'xxxx', ['X-Secret-Value'] = '42' }local r = http_client.post('http://localhost:8081', data, { headers = headers})if r.status == 200 then    print 'Success'end

http_server.lua

Используйте rock-пакет http -- сторонний модуль, который необходимо предварительно установить, -- чтобы превратить Tarantool в веб-сервер.

#!/usr/bin/env tarantoollocal function handler(self)    return self:render{ json = { ['Your-IP-Is'] = self.peer.host } }endlocal server = require('http.server').new(nil, 8080, {charset = "utf8"}) -- listen *:8080server:route({ path = '/' }, handler)server:start()-- connect to localhost:8080 and see json

http_generate_html.lua

Используйте rock-пакет http -- сторонний модуль, который необходимо предварительно установить, -- чтобы создавать HTML-страницы на основе шаблонов. В стороннем модуле http есть достаточно простой движок шаблонов, который позволяет выполнять регулярный код на Lua в текстовых блоках (как в PHP). Таким образом, не нужно изучать новые языки, чтобы писать шаблоны.

#!/usr/bin/env tarantoollocal function handler(self)local fruits = {'Apple', 'Orange', 'Grapefruit', 'Banana'}    return self:render{ fruits = fruits }endlocal server = require('http.server').new(nil, 8080, {charset = "utf8"}) -- nil means '*'server:route({ path = '/', file = 'index.html.lua' }, handler)server:start()

HTML-файл для этого сервера, включая Lua, может выглядеть следующим образом (будет выведено "1 Apple \| 2 Orange \| 3 Grapefruit \| 4 Banana"):

<html><body>    </body></html>

Создайте директорию templates и поместите в неё файл.

select_all.go

На языке Go выборка содержимого всего спейса не является тривиальной задачей, которая решается в одну строчку. Ниже мы приводим пример программы, которая осуществляет полную выборку из спейса 'tester'. Эту программу нужно вызвать на том экземпляре, с которым вы собираетесь установить соединение через Go-коннектор.

cookbook/main.go