я знаю, что теперь вы можете создавать постоянные переменные в Lua с помощью <const>, но, похоже, они работают только с локальными переменными:
local myNumber <const> = 10 -- This works perfectly fine
myGlobalNumber <const> = 10 -- This causes an error
Возможно ли также иметь постоянные глобальные переменные?
myGlobalNumber <const> = 10
Вы можете моделировать константные глобальные переменные с помощью метатаблицы _G.





Цель атрибута локальной переменной <const> — позволить Lua проверить во время «загрузки» (когда вы вызываете dofile / load / require или аналогичный), не мутируется ли локальная переменная - то есть, является ли единственное присвоение начальный во время объявления. Это инструмент, помогающий программистам (1) выразить намерение (2) получить немного больше проверок «времени загрузки», чем просто синтаксические проверки.
Это работает для переменных local именно потому, что они локальны. Они видны только внутри области действия функции. Это означает, что у Lua есть вся необходимая информация, когда вы загружаете «кусок» кода (фактически тело функции), чтобы проверить, соответствует ли он статическим (время загрузки) правилам <const>.
«Глобальные переменные» / «переменные среды» (как я их называю) по сути являются просто синтаксическим сахаром для доступа к полям в таблице _ENV (обычно _G). По существу, они гораздо более динамичны, чем локальные переменные. Например, вы можете сделать _G[some .. complex .. expression] = 42. С глобальными переменными, как и с любыми другими полями таблицы, Lua не имеет всей необходимой информации во время загрузки. Во-первых, он даже не знает, какие поля ваш код установит или получит. Даже если бы он знал это или ограничился синтаксисом <name>, этого все равно было бы недостаточно. Рассмотрите возможность загрузки файла, в котором используется определенная глобальная переменная, которая еще не была установлена (возможно, в каком-то обратном вызове, где автор знает, что она будет доступна со временем). Lua не может предупредить об этом во время загрузки файла. (В лучшем случае он может попытаться предупредить при загрузке файла, содержащего конфликтующие определения констант, а затем предупредить при загрузке последующих файлов.)
Как сказал ESkri, вы можете реализовать проверки во время выполнения, чтобы защититься от доступа к постоянным глобальным переменным через метатаблицу. Это может выглядеть примерно так:
local constants = {pi = math.pi}
setmetatable(_G, {__index = constants, __newindex = function(_, key) error("attempt to change constant global variable " .. key) end})
print(pi) -- runs fine
pi = 3 -- errors
Однако это, вероятно, плохая идея:
Вместо этого я бы рекомендовал использовать инструменты статического анализа, такие как Luacheck, который позволяет вам указывать [глобальные переменные, доступные только для чтения, в его файле конфигурации, а также поддерживает встроенную опцию new read globals для добавления глобальных переменных только для чтения, аналогично «постоянное» определение. Пример:
-- luacheck: globals pi
pi = math.pi
-- luacheck: new read globals pi
pi = 3
Следует отметить, что, хотя область действия параметров ограничена файлами, поле конфигурации read_global относится к каждому «проекту» (папке), в котором вы запускаете Luacheck. Чтобы установить pi как глобальный объект только для чтения для всего проекта, вы можете установить read_globals = {"pi"}, затем используйте -- luacheck: globals pi, чтобы создать исключение там, где определен pi (с последующим -- luacheck: new read globals pi, чтобы впоследствии отменить это исключение).
Константами могут быть только локальные переменные. Никаких глобальных. Нет полей таблицы. На самом деле это совершенно бесполезная функция Lua.