2009-05-22 3 views
2

Предположим, у меня есть имя файла «test.lua», содержащие строки ниже:Как получить закрытие в lua?

--[[ test.lua --]] 
local f = function() 
    print"local function f in test.lua" 
end 

f_generate = function() 
    local fun = loadstring(" f()") 
-- local env = getfenv(1) 
-- set(fun,env) 
    return fun 
end 
f_generate()() 
--[[ end of test.lua--]] 

потому LoadString делать свои вещи в рамках глобальной окружающей среды, поэтому, когда я называю f_generate()() я получите ошибку msgstr "попытка вызвать глобальный 'f' (значение nil)"

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

Причина table - единственная структура данных в lua, (и функциональная среда и другие объекты реализуются таблицей), я думаю, разумно предположить, что закрытие также реализуется таблицей, но как я могу ее получить ?

ответ

0

Я думаю, вы смешиваете две разные вещи:

  1. закрытия: для этого, определение F() должна быть внутри сферы из любой локальной переменной вы хотите вложить.

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

Помните: сфера является лексической, в то время как окружающая среда, что каждая функция считает «глобальное пространство».

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

BTW, интерфейс «отладки», давайте встретимся с локальными переменными функции, поэтому может быть и так. Я просто не чувствую необходимости делать это.

0

Вы должны удалить 'local', иначе это будет собранный мусор.

--local f = function() 
f = function() 
    print"local function f in test.lua" 
end 
4

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

 
-- test.lua 
local f = function() 
    print"local function f in test.lua" 
end 

f_generate = function() 
    local fun = function() return f() end 
    return fun 
end 
f_generate()() 
-- end of test.lua 

мотивация понятнее, если есть параметр f_generate:

 
-- test.lua 
local f = function(y) 
    print("local function f("..y..") in test.lua") 
end 

f_generate = function(name) 
    local fun = function() return f(name) end 
    return fun 
end 
f_generate("foo")() 
f_generate("bar")() 
-- end of test.lua 

Переход через анализатор с loadstring() явно принимает код за рамки вызова до loadstring(). Локальные переменные не сохраняются в любой таблице окружения. Они реализованы так же, как и на любом другом языке: хранилище для них выделяется генератором кода и недоступно вне этой компиляции. Конечно, модуль отладки (и API) имеет возможность заглядывать в них, но это никогда не рекомендуется использовать за пределами отладчика.

Правильный способ сохранения ссылки на локальный язык для использования за пределами области действия является истинным повышением к закрытию. Именно это достигается fun = function() return f() end. В этом случае значение f сохраняется как верхнее значение функции, сохраненной в fun.Обратите внимание, что на практике эта обертка как upvalue довольно эффективна. Поиск нужного имени не требуется, чтобы найти значение, и поскольку я использовал хвостовой вызов, дополнительных кадров стека не требуется.

+0

локальная __cmp__table = { [ ">"] = функция (а, б) возвращают> конец B, [ "> ="] = функция (а, б) возвращают конец а> = B, [ "<"] = функция (a, b) возвращает a gray

+0

Это настоящий код, кажется, что мне действительно нужна loadstring, любое предложение? и отбросить все практические нужды и обходные пути, мы все же можем говорить о возможности получить закрытие, ведь закрытие является активной цепочкой записей функции (исправьте меня, если ...), и я думаю, что lua реализует ее как table (потому что вся вещь может быть реализована как таблица ...; опять же, исправьте меня, если ...) спасибо большое, это действительно помогает. – gray

+0

@gray: нет, замыкания и локальные переменные кадры не являются таблицами. – Javier

0

См., Вы не можете обрабатывать функции/замыкания в виде таблиц. Рассмотрим следующий код:

local table = { 
    baz = { 
     blah = "bar" 
    }, 
    foo = table.baz.blah 
} 

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

Теперь, фиксируя код:

local __cmp__table = { 
    [">"] = function(a,b) return a>b end, 
    [">="] = function(a,b) return a>=b end, 
    ["<"] = function(a,b) return a<b end, 
    ["<="] = function(a,b) return a<=b end, 
    ["=="] = function(a,b) return a==b end, 
    ["~="] = function(a,b) return a~=b end, 
} 
cmp = function(a, op, b) 
    return __cmp__table[op](a,b) 
end 

Это позволит вам звонить на любые ХМП двух переменных с правильной функцией сравнения. Если я пропустил пункт о вашем коде, то, пожалуйста, скажите мне!