Установите другую среду для одной и той же функции в Lua 5.1

Я хотел бы установить разные среды для одной и той же функции в Lua 5.1 (luajit):

f = function() print(a) end
b = setfenv(f, { a = 1, print = print })
c = setfenv(f, { a = 2, print = print })

Я хотел бы, чтобы b() и c() печатали разные числа

Я взломал способ, создав новые фрагменты функций на основе string.dump и привязав к нему env, но есть ли лучший, более элегантный способ? В качестве альтернативы, может ли функция каким-то образом иметь разные значения upvalue в зависимости от некоторого условия?

function bind_env(f, env)
  return setfenv(loadstring(string.dump(f)), env)
end

Спасибо!


person nehz    schedule 21.08.2014    source источник
comment
Менять окружение перед каждым вызовом: b = function(...) return setfenv(f, b_env_table)(...) end. Может быть, это было бы достаточно быстро ;-)   -  person Egor Skriptunoff    schedule 21.08.2014
comment
Круто, лучший хак, чем перекомпиляция чанков :) Сначала я думал, что это не сработает с сопрограммами, но мне просто нужно установить env перед возобновлением и сбросить его после.   -  person nehz    schedule 21.08.2014


Ответы (1)


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

function test(a, b)
   function func(x) -- sees x, a and b
       print(a*x+b)
   end
   return func
end

f12 = test(1, 2) -- x+2
f23 = test(2, 3) -- 2x+3

f12(4)
f23(4)

Последние две строки выводят 6 и 11. Технически test(a,b) возвращает другой объект функции для каждого a, b, но теоретически он возвращает разные замыкания одной и той же функции (одна и та же последовательность байт-кодов). Итак, если бы у вас было

function func(a)
    return function() print(a) end
end 

вы можете определить другое закрытие для каждого a:

b = func(1) -- a=1
c = func(2) -- a=2

Однако обратите внимание, что b==c ложно, но это, вероятно, хорошо.

person Oliver    schedule 02.09.2014