2011-12-20 3 views
1

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

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

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

ответ

6

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

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) 

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

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

То есть, как вы могли бы сделать это!

... если ..

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

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

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

Вы должны проявлять осторожность при использовании этой библиотеки. Предоставленные здесь функции должны использоваться исключительно для отладки и подобных задач, таких как профилирование. Не поддавайтесь искушению использовать их в качестве обычного инструмента программирования: они могут быть очень медленными. Более того, некоторые из этих функций нарушают некоторые предположения относительно кода 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) и выше версию требует, чтобы запустить функцию.
Кажется безнадежным!

... если ..

..you действительно нарушать правила.
Функция debug.sethook позволяет прерывать запуск кода Lua на определенных событиях и даже изменять вещи, пока все это происходит. Это, в сочетании с coroutines, позволяет вам делать некоторые интересные хакеры.
Вот реализация 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

С выпуском 5.2 они немного смягчают ограничение.Уведомление в руководстве перешло от «Пожалуйста, сопротивляйтесь искушению использовать их в качестве обычного инструмента программирования» на «Вы должны проявлять осторожность при использовании этой библиотеки». Поэтому будьте осторожны и знаете, что вы делаете, но вы можете использовать это :). – jpjacobs

+1

Комплексный ответ :) Просто сделаем небольшую заметку о том, что имя функции в соответствии с библиотекой отладки не берется из разбора, а из имени, используемого для вызова функции во время выполнения. – MattJ

+0

Хорошо, что объясняет, почему 'debug.getfuncname' почти никогда не работает ... – Deco

1

Функция не имеет никакого имени. Если вы хотите, вы можете присвоить его имени переменной:

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

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

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

table.insert(t, 1, theFunction) 

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

+0

Спасибо, за ответ. Мне нужно, чтобы получить имя функции из этой таблицы. Но для вызова функции я буду использовать числовой индекс. Как мне это сделать? –

0

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

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

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

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

0

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

functions = {} 
functionNames = {} 

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

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

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

Удачи!