LUA Как использовать __mode в метатаблицах
Насчет __mode
совсем недавно узнал как работает. Штука очень классная и полезная.
По-простому объясняя, нужно понимать, что сборщик мусора считает мусором те данные, на которые больше нигде не осталось ссылок.
Сами ссылки ты устанавливаешь, когда например добавляешь данные в таблицу. Пример:
local arr = {}
QWE[1] = arr
Теперь на таблицу arr
установлена одна сильная ссылка. Если сделать QWE[1] = nil
, то ссылок больше не останется и сборщик потом удалит эту табличку
__mode
позволяет устанавливать таблицам инструкцию, что закрепленные за ней ключи или значения не будут создавать сильные ссылки (они называются слабыми)
Если мы сделаем setmetatable(QWE, {__mode = "v"})
(тем самым сказав, что значения таблицы QWE не считаются сильными ссылками) и повторим наш QWE[1] = arr
, то сборщик мусора зачистит наш arr
и при print(QWE[1])
после работы сборщика отпринтит nil
Слабыми можно делать и ключи, тогда нужно указать mode "v". Или и ключи и значения: "kv".
Реальное применение
Я узнал об этом совсем недавно, но успел применить так: в новой версии IGS полностью переписан API framework. Репитер упавших запросов сделан отдельным модулем. Так вот тот репитер повторяет запросы, которые по некоторым причинам провалились, но делает это не более 15 раз.
В качестве счетчика используется ключ-значение таблица, где ключом выступает сама функция, а значением число раз, которое я пытался ее выполнить. Напоминаю, что в Lua функции передаются ссылками. Так вот ключи этой таблицы я сделал слабыми ссылками и если функция удаляется сборщиком где-то из вне, то ее счетчик в таблице так же автоматически очищается и мне не приходится следить за этим "вручную".