Распечатать все локальные переменные, доступные для текущей области в Lua

Я знаю, как напечатать "все" глобальные переменные, используя следующий код

for k,v in pairs(_G) do
    print("Global key", k, "value", v)
end

Поэтому мой вопрос заключается в том, как это сделать для всех переменных, которые доступны из выполняемой в данный момент функции, что может сделать то, что locals() делает для Python.

5 ответов

Решение

Вот реализация locals() функция. Он вернет таблицу локальных пользователей из области вызова:

function locals()
  local variables = {}
  local idx = 1
  while true do
    local ln, lv = debug.getlocal(2, idx)
    if ln ~= nil then
      variables[ln] = lv
    else
      break
    end
    idx = 1 + idx
  end
  return variables
end

Обратите внимание, что в lua REPL каждая строка представляет собой отдельный кусок с отдельными местными жителями. Также возвращаются внутренние переменные (имена начинаются с '(', если вы хотите удалить их):

> local a = 2; for x, v in pairs(locals()) do print(x, v) end
a   2
(*temporary)    function: 0x10359b38

Спасибо за согласие. Вы открыли последний кусок головоломки!;-)

Повышающие значения - это локальные переменные из внешних областей, которые используются в текущей функции. Они ни в _G ни в locals()

function upvalues()
  local variables = {}
  local idx = 1
  local func = debug.getinfo(2, "f").func
  while true do
    local ln, lv = debug.getupvalue(func, idx)
    if ln ~= nil then
      variables[ln] = lv
    else
      break
    end
    idx = 1 + idx
  end
  return variables
end

Пример (обратите внимание, вы должны использовать для этого, чтобы показать):

> local a= 2; function f() local b = a; for x,v in pairs(upvalues()) do print(x,v) end end; f()
a   2

Использование debug.getlocal,

Проблема с версией петли судьи Мейгардена просто local i = 0, Это ничего не делает, потому что первый индексированный с '0' всегда будет возвращать ноль.

Помните, что индексы Lua по умолчанию начинаются с "1", а не с "0", как C/C++. Конечно, вы можете использовать '0' для индекса с вашими собственными типами, но функции по умолчанию ожидают значение по умолчанию '1' в качестве первого индекса.

Просто измените это на local i = 1 и его цикл будет работать нормально.

Увидеть debug.getlocal:

local foobar = 1

local i = 0
repeat
    local k, v = debug.getlocal(1, i)
    if k then
        print(k, v)
        i = i + 1
    end
until nil == k

Выход:

foobar  1
i       2

Вы можете использовать getfenv, чтобы получить локальную среду.

getfenv ([f]) Возвращает текущее окружение, используемое функцией. f может быть функцией Lua или числом, которое определяет функцию на этом уровне стека: уровень 1 - это функция, вызывающая getfenv. Если данная функция не является функцией Lua или если f равно 0, getfenv возвращает глобальную среду. Значением по умолчанию для f является 1.

Изменить: извините, я был не прав.

Я только что проверил исходный код Lua. debug.getlocal() это единственный способ получить локальные переменные.
Lua использует внутреннюю структуру Proto и не дает нам доступа к этому.
(Proto содержит локальные свойства плюс родительскую ссылку на Proto. Итерация функции Proto с помощью getfenv,
мы также перебираем наследуемые свойства, а не то, что хотели)

Пользователи могут определять свои Proto- ы либо с помощью сред и set/getfenv функции или с помощью метатаблиц.

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