Глобальные константные переменные в lua 5.4

я знаю, что теперь вы можете создавать постоянные переменные в Lua с помощью <const>, но, похоже, они работают только с локальными переменными:

local myNumber <const> = 10 -- This works perfectly fine

myGlobalNumber <const> = 10 -- This causes an error

Возможно ли также иметь постоянные глобальные переменные?

myGlobalNumber <const> = 10

Константами могут быть только локальные переменные. Никаких глобальных. Нет полей таблицы. На самом деле это совершенно бесполезная функция Lua.

ESkri 31.03.2024 18:50

Вы можете моделировать константные глобальные переменные с помощью метатаблицы _G.

ESkri 31.03.2024 18:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
187
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Цель атрибута локальной переменной <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, чтобы впоследствии отменить это исключение).

Другие вопросы по теме