Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
[Обучение] Основы Lua.docx
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
66.67 Кб
Скачать

Примеры использования мета-таблиц

Значение по умолчанию для полей таблиц

В следующем примере мета-таблицы используются для назначения значения по умолчанию для отсутствующих элементов таблицы:

function set_def(t, v)

local mt = { __index = function() return v end }

setmetatable(t, mt)

end

Вот более нетривиальное решение, которое не использует отдельной мета-таблицы для каждого умалчиваемого значения:

local key = {}

local mt = { __index = function(t) return t[key] end }

function set_def(t, v)

t[key] = v

setmetatable(t, mt)

end

Здесь локальная (пустая) таблица key используется как заведомо уникальный индекс, по которому в исходной таблице t сохраняется умалчиваемое значение v. Все таблицы, для которых устанавливается умалчиваемое значение отсутствующих полей, разделяют общую мета-таблицу mt. Мета-метод __index этой мета-таблицы перехватывает обращения к отсутствующим полям таблицы и возвращает значение, сохраненное в самой таблице по индексу key.

У этого решения есть недостаток: в таблице появляется новая пара ключ-значение, которая проявится при попытке обойти все элементы таблицы.

Таблица-прокси

В следующем примере пустая таблица выполняет роль прокси, переадресующего обращения к полям таблицы:

local key = {}

local mt = {

__index = function(t,k)

return t[key][k]

end,

__newindex = function(t,k,v)

t[key][k] = v

end

}

function proxy(t)

local proxy = {}

proxy[key] = t

setmetatable(proxy, mt)

return proxy

end

Здесь локальная (пустая) таблица key используется как заведомо уникальный индекс, по которому в таблице-прокси сохраняется ссылка на исходную таблицу t. Прокси представляет собой таблицу, единственный элемент которой имеет индекс key, поэтому обращение к любому элементу прокси приведет к вызову мета-метода. Общая для всех прокси мета-таблица определяет мета-методы __index и __newindex, извлекающие исходную таблицу из единственного элемента прокси, индексируя его таблицей key.

Мета-методы могут обеспечить произвольную дисциплину обработки обращений к полям исходной таблицы. Простыми примерами является протоколирование обращений или генерирование ошибки при попытке изменить значение элемента таблицы.

«Слабые» таблицы

Если объект был использован как индекс таблицы или ссылка на него была сохранена в таблице, то сборщик мусора не сможет утилизировать такой объект. В то же время, в некоторых случаях желательно иметь таблицу, в которой связь ее элементов с ключами и/или значениями «слабая» т.е. не препятствующая сбору мусора. Обычно такая необходимость возникает при кэшировании результатов вычислений в таблице и сохранении атрибутов объектов в таблице, проиндексированной самими объектами. В первом случае желательна слабая связь для значений, во втором  —  для индексов.

Связь элементов таблицы с объектами (значениями и индексами) определяется значением строкового поля __mode ее мета-таблицы. Если это поле содержит символ 'k', то слабой делается связь для индексов (ключей); если оно содержит символ 'v', то слабой делается связь для значений. Поле может содержать оба символа, что сделает слабой связь как для индексов, так и для значений.

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

local defaults = {}

setmetatable(defaults, { __mode = "k" })

local mt = { __index = function(t) return defaults[t] end }

function set_def(t, d)

defaults[t] = d

setmetatable(t, mt)

end

Вот другое решение, в котором слабая таблицы хранит мета-таблицы, количество которых совпадает с числом различных умалчиваемых значений:

local metas = {}

setmetatable(metas, { __mode = "v" })

function set_def(t, d)

local mt = metas[d]

if mt == nil then

mt = { __index = function () return d end }

metas[d] = mt

end

setmetatable(t, mt)

end