Как установить имя для функции, которая находится в таблице - PullRequest
1 голос
/ 20 декабря 2011

Например, у меня есть таблица

table.insert( t, 1, function()
                        print ("rock");
                    end );

Есть ли способ получить имя функции из этой таблицы.Я знаю, что могу хранить имя как ключ, но что, если я хочу сохранить числовой индекс, а также узнать имя функции?Есть ли способ сделать это?Спасибо, заранее.

Ответы [ 4 ]

6 голосов
/ 20 декабря 2011

скажем, у вас есть этот код:

t = {}
x = 5
table.insert(t, 1, x)

t тогда будет {[1] = 5}. «5» - это просто число - оно не имеет имени и не связано с переменной «x»; это значение .
В Lua функции обрабатываются точно так же, как значения :

t = {}
x = function() print("test! :D") end
table.insert(t, 1, x)

Значение x никак не связано с x, ни формой, ни формой. Если вы хотите вручную назвать функцию, вы можете сделать это, поместив функцию в таблицу, например:

t = {}
x = function() print("test! :D") end
table.insert(t, 1, {
    name = "MyFunctionName",
    func = x
})

Вот как бы вы это сделали!

... если ..

.. вы нарушаете правила!
Когда был разработан Lua, разработчики поняли, что анонимный характер функций затруднит создание продуктивных сообщений об ошибках, если не будет невозможным.
Лучшее, что вы увидите, будет:

stdin: some error!
  stdin: in function 'unknown'
  stdin: in function 'unknown'

Итак, они сделали так, чтобы при разборе кода Lua он записывал некоторую отладочную информацию, чтобы облегчить жизнь. Для доступа к этой информации из самого Lua предоставляется библиотека отладки .
Будьте очень осторожны с функциями в этой библиотеке.

Вы должны проявлять осторожность при использовании этой библиотеки. Функции, представленные здесь, должны использоваться исключительно для отладки и подобных задач, таких как профилирование. Пожалуйста, не поддавайтесь искушению использовать их как обычный инструмент программирования: они могут быть очень медленными. Более того, некоторые из этих функций нарушают некоторые предположения о коде Lua (например, что локальные для функции переменные не могут быть доступны извне или что метатаблицы пользовательских данных не могут быть изменены кодом Lua) и, следовательно, могут поставить под угрозу безопасность кода в противном случае. .

Для достижения желаемого эффекта вы должны использовать функцию debug.getinfo; пример:

x = function()
    print("test!")
    print(debug.getinfo(1, "n").name)
end
x() -- prints "test!" followed by "x"

К сожалению, форма debug.getinfo, которая работает непосредственно с функцией, не заполняет аргумент name (debug.getinfo(x, "n").name == nil), и в приведенной выше версии вам необходимо запустить функцию.
Кажется безнадежным!

... если ..

.. Вы действительно нарушаете правила.
Функция debug.sethook позволяет вам прерывать выполнение кода Lua при определенных событиях и даже изменять вещи, пока все это происходит. Это, в сочетании с сопрограммами , позволяет делать интересные вещи.
Вот реализация debug.getfuncname:

function debug.getfuncname(f)
    --[[If name found, returns
            name source line
        If name not found, returns
            nil  source line
        If error, returns
            nil  nil    error
    ]]
    if type(f) == "function" then
        local info = debug.getinfo(f, "S")
        if not info or not info.what then
            return nil, nil, "Invalid function"
        elseif info.what == "C" then
            -- cannot be called on C functions, as they would execute!
            return nil, nil, "C function"
        end
        --[[Deep magic, look away!]]
        local co = coroutine.create(f)
        local name, source, linedefined
        debug.sethook(co, function(event, line)
            local info = debug.getinfo(2, "Sn")
            name = info.namewhat ~= "" and info.name or nil
            source, linedefined = info.short_src, info.linedefined
            coroutine.yield() -- prevent function from executing code
        end, "c")
        coroutine.resume(co)
        return name, source, linedefined
    end
    return nil, nil, "Not a function"
end

Пример использования:

function test()
    print("If this prints, stuff went really wrong!")
end

print("Name = ", debug.getfuncname(test))

Эта функция не очень надежна - иногда она работает, а другие нет. Библиотека отладки очень обидчива, так что этого следовало ожидать.

Обратите внимание, что вы никогда не должны использовать это для фактического кода выпуска! Только для отладки!
Самый крайний случай, который все еще приемлем, - это регистрация ошибок на части выпущенного программного обеспечения, чтобы помочь разработчику решить проблемы. Никакой жизненно важный код не должен зависеть от функций из библиотеки отладки.

Удачи!

1 голос
/ 20 декабря 2011

У функции нет имени.Если вы хотите, вы можете назначить ее именованной переменной:

theFunction = t[1]
-- Call it:
theFunction()

Если вы хотите сохранить именованную функцию в таблице, определите ее заранее и используйте ее имя для хранения:

theFunction = function()
                  print ("rock");
              end

table.insert(t, 1, theFunction)

Если это не то, что вы имели в виду, дайте больше подробностей;например, как вы хотели бы получить доступ к функции.Ваш вопрос немного туманный.

0 голосов
/ 20 декабря 2011

Вы можете хранить имена в отдельной таблице.

functions = {}
functionNames = {}

function addFunction(f, name)
  table.insert(functions, f)
  functionNames[name] = f
end

Чтобы получить функцию, вы можете использовать индекс. Если у вас есть функция, вы можете получить ее имя из function_names:

f = functions[3]
name = functionNames[f]

Удачи!

0 голосов
/ 20 декабря 2011

Дело в том, что table.insert рассматривает таблицу как последовательность, только с цифровыми клавишами.

Если вы хотите иметь возможность вызывать функцию как t.fun(), вам придется использовать таблицу какассоциативный массив и, следовательно, использовать строку в качестве ключа.(Кстати, любой тип, кроме nil или NaN, разрешен в качестве ключа)

t={}
t['MyFun']=function print'foo' end
t.myFun() -- uses syntactic sugar for string keys that are valid identifiers.

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

...