Lua: строка загрузки внутри функции, по-видимому, не работает?

#lua

Вопрос:

Внутри функции ( doloadstring ) я заметил, что loadstring даже при передаче правильной строки переменная функции не изменяется. Что это дает?

Я предполагаю x , что это локальная переменная и loadstring имеет только глобальную область действия?`

 print('this works as I expect')
x = 0
loadstring('x = 1')()
print(x)

print('this does not')
function doloadstring(x, s)
    print(x)
    loadstring(s)() -- loadstring does not appear to change a variable in a function, is it because x is local
    print(x)
    print(z)
end

doloadstring('0', 'x = 1') -- x is not changed
doloadstring('0', 'z = 1') -- z is created tho
 

Это и есть результат:

 this works as I expect
1
this does not
0
0
nil
0
0
1
 

Ответ №1:

Да, результат заключается в том, что эта переменная x не существует в среде, которую получает функция (эти две переменные никак не связаны). Существуют такие функции, как debug.upvaluejoin, debug.setupvalue и debug.setlocal, но ни одна из них не «соединит» локальную переменную с функцией upvalue, чтобы сделать их одинаковыми.

Вы можете сделать следующее: (1) Создание новой среды, (2) внести (значения) локальные переменные и upvalues, (3) вызывать функцию с этой среды (пропуск среды load для Lua 5.2 или использовать setfenv в Lua 5.1), и тогда (4) примет любые изменения от окружения и назначить их в локальных переменных/upvalues (вы можете использовать прокси-таблицы, чтобы упростить обнаружение изменений).

Вы можете проверить функции restore_vars и capture_vars из Mobdebug, которые делают что-то подобное. Это решает проблему в наиболее общем виде (когда вы не имеете никакой информации о переменных, которые могут быть использованы в свой «заряженный» функция), так что если у вас есть информация об этом, вы, безусловно, можете упростить логику и пройти определенную среду, которая соответствует тому, что вам нужно (вам не нужно, чтобы захватить все upvalues и локальные переменные).

Комментарии:

1. Спасибо! Довольно банальное решение, которое я бы сделал, — это просто создать временную глобальную переменную в качестве заполнителя и сделать строку под x.

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