Есть ли простой способ получить все глобальные переменные, определенные в файле кода Lua?

Я предпочитаю, чтобы прослушиватели событий были развернуты модульной функцией, а не сценарием прослушивателя событий уровня document. Итак, мне нравится ниже. Обратите внимание: вы не можете переадресовать элемент с одним и тем же прослушивателем событий, поэтому не беспокойтесь о прикреплении слушателя более одного раза - только один палец.

var iterations = 4;
var button;
var body = document.querySelector("body");

for (var i = 0; i < iterations; i++) {
    button = document.createElement("button");
    button.classList.add("my-button");
    button.appendChild(document.createTextNode(i));
    button.addEventListener("click", myButtonWasClicked);
    body.appendChild(button);
}

function myButtonWasClicked(e) {
    console.log(e.target); //access to this specific button
}

2
задан SuperSaiyanGod 28 March 2019 в 03:02
поделиться

2 ответа

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

Lua предоставляет компилятор luac, который принимает аргумент -l для списка.

В Lua 5.1 есть код операции SETGLOBAL. В столбце указывается номер строки оператора, а в комментарии указывается имя глобального.

В 5.2 и позже, есть код операции SETTABUP. Столбец указывает номер строки оператора, а комментарий - имя таблицы и ключ. «Глобалы» находятся в таблице, на которую ссылается значение _ENV.

Итак, вы можете легко найти номер строки любого оператора, который устанавливает глобальную переменную, с помощью инструментов, предоставляемых Lua.

Кстати, во многих модульных системах скрипт модуля не устанавливает глобальных переменных.

0
ответ дан Tom Blodget 28 March 2019 в 03:02
поделиться

У Луа нет способа узнать, когда или где был представлен глобал.

В частности, что значение является функцией, debug.getinfo может помочь, сообщив вам, где определена функция (что часто, но не всегда, является тем же местом, где функция делается глобальной).

Вы можете получить необходимую информацию во время представления глобала. Это может быть сделано путем установки метатаблицы с помощью метода __newindex в глобальной таблице. Этот метод будет вызываться, когда вводится новый глобал (но не тогда, когда существующий глобал переопределяется). В этом методе вы можете выяснить, откуда пришел вызывающий с debug.getinfo. Также будьте осторожны, если любой другой ваш код пытается использовать метатаблицу в глобальной среде, вы должны хорошо с ней поиграть. (Он может иметь только одну метатаблицу.)

Вы также можете избежать использования глобальной таблицы. Один из промежуточных способов сделать это - переопределить окружение. В Lua 5.2 и Lua 5.3 это делается путем объявления локальной таблицы с именем _ENV - вместо этого все обращения к глобальной таблице будут иметь доступ к этой таблице. (На самом деле, глобальные доступы всегда используют _ENV и _ENV по умолчанию _G.) Вы можете сделать это главным образом невидимым, предоставив метатаблице _ENV, которая перенаправляет доступ к _G (или любой другой среде). Разница здесь в том, что __newindex будет по-прежнему вызываться, даже если в _G существует привязка, поэтому этот метод может обнаруживать переопределения.

Использование _ENV, хотя по своей природе является локальным для области (например, каждый файл должен переопределять его). Такой крюк может быть установлен и во всем мире. Если вы загружаете свои модули вручную с помощью функции load (маловероятно), вы можете просто предоставить пользовательский _ENV в качестве аргумента. Если вы используете require, можно получить удержание загруженного файла перед его выполнением, переопределив (или установив патчи) поиск Lua в package.searchers[2]. Это встроенная функция, которую require вызывает, чтобы найти файл в вашей файловой системе и затем загрузить его. Возвращаемым значением является загруженная функция, которая затем запускается require. Таким образом, после загрузки, но до возвращения обратно в require, вы можете использовать debug.setupvalue для переопределения значения по умолчанию _ENV (если есть).

Пример кода (только слегка проверенный):

local global_info = {}

local default_searcher2 = package.searchers[2]

package.searchers[2] = function(...)
  local result = default_searcher2(...)
  local parent_environment = _G
  local my_env = setmetatable({}, {
    __index = parent_environment,
    __newindex = function(self, k, v)
      local new_info = debug.getinfo(2)

      -- keeping rich data like this could be a memory leak
      -- if some globals are assigned repeatedly, but that
      -- may still be okay in a debugging scenario
      local history = global_info[k]
      if history == nil then
        history = {}
        global_info[k] = history
      end
      table.insert(history, {info = new_info, value = v})

      parent_environment[k] = v
    end,
  })
  if type(result) == "function" then
    debug.setupvalue(result, 1, my_env)
  end
  return result
end

function gethistory(name)
  local history = global_info[name]
  if history == nil then
    print('"' .. name .. '" has never been defined...')
  else
    print('History for "' .. name .. '":')
    for _, record in ipairs(history) do
      print(record.info.short_src .. ": " .. record.info.currentline)
    end
  end
end

Обратите внимание, что здесь ловушка будет применяться только к файлам, требуемым после запуска этого кода, и в основном применяется только к файлам Lua (не C libs) которые включаются через встроенный require. Он не устанавливает метатаблицы в глобальной среде, поэтому не конфликтует, но его можно обойти, если файлы обращаются к _G напрямую (или, например, настраивают доступ к _G вместо _ENV в своих собственных таблицах _ENV ). Такие вещи также могут быть учтены, но это может быть кроличья нора в зависимости от того, насколько «невидимым» вам нужен этот патч.

В Lua 5.1 вместо _ENV у вас есть setfenv, который, я считаю, может быть использован для аналогичного эффекта.

Также обратите внимание, что все методы, которые я выделяю, могут обнаруживать только глобальные обращения, которые фактически выполняются во время выполнения.

0
ответ дан tehtmi 28 March 2019 в 03:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: