2015-10-24 1 views
4

Предположим, у меня есть следующие два Lua файлы:Локальная переменная не видна в закрытии по файлу?

В a.lua:

local x = 5 
f = dofile'b.lua' 
f() 

В b.lua:

local fun = function() 
    print(x) 
end 
return fun 

Тогда, если я бегу luajit a.lua в скорлупе он печатает nil так x нельзя увидеть в функции, определенной в b.lua. Ожидаемая печать должна быть 5. Однако, если я ставлю все в одном файле, то это именно то, что я хочу:

В aa.lua:

local x = 5 
local f = function() 
    print(x) 
end 
f() 

Run luajit aa.lua печатает 5.

Так почему же x не видно в первом случае?

ответ

4

Как следует из их названия, локальные переменные являются локальными для куска.

dofile() загружает кусок из другого файла. Поскольку это еще один кусок, имеет смысл, что локальная переменная x в первом фрагменте не рассматривается ею.

+0

Спасибо за ваш ответ! Еще одна вещь: если тело функции 'fun' слишком велико, что я не хочу помещать его в файл' a.lua', а отдельный файл (как то, что я делаю в первом случае, который doesn ' t work), есть ли какая-нибудь хорошая идиома, чтобы заставить ее работать? –

1

Я согласен, что это несколько неинтуитивно, что это не работает.

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

Когда вы загружаете кусок с использованием файла dofile, он может видеть, какие существуют глобальные переменные в настоящее время, но, по-видимому, он не видит никаких локальных переменных. Мы знаем, что «dofile» не похож на макросы включения C/C++, что даст точно то поведение, которое вы описываете для локальных переменных, но все же вы можете разумно ожидать, что эта его часть будет работать одинаково.

В конечном счете нет ответа, но «это не так, как они указали язык». Единственный , удовлетворяющий ответ, вероятно, по строкам ', потому что иначе это вызовет неочевидную проблему X' или ', потому что тогда случай использования Y будет медленнее.

Я считаю, что лучшим ответом является то, что если все имена динамически восстанавливаются в соответствии с областью, в которой они загружаются при использовании loadfile/dofile, это будет препятствовать большой оптимизации и тому подобное при компиляции блоков в байт-код. В системе lua разрешение имен работает как «либо локально в этой области, а затем привязывается к этому (известному) объекту, или же это поиск в (уникальной) глобальной таблице». Эта система довольно проста, есть только несколько вариантов и не много места для сложности.

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


Если ваш вопрос не совсем почему но как я могу заставить его работать в любом случае, то один из способов вы можете сделать это, в главном сценарии, ставить какие-либо локальные переменные, которые вы хотите быть видимый в среде сценария, который вызывается. Когда вы это делаете, вам нужно разделить dofile на несколько вызовов. Это немного отличается в lua 5.1 vs lua 5.2.

В Lua 5.1:
В a.lua:

local shared = { x = 5 } 
temp = loadfile('b.lua') 
setfenv(temp, shared) 
f = temp() 
f() 

В Lua 5.2:
В a.lua:

local shared = { x = 5 } 
temp = loadfile('b.lua', 't', shared) 
f = temp() 
f() 
+0

Спасибо за ваше длинное и терпеливое объяснение! Просто связанный вопрос, который я также размещаю ниже другого ответа: если тело функции 'fun' слишком велико, что я не хочу помещать его в файл' a.lua', а отдельный файл (как то, что я делать в первом случае, который не работает), есть ли хорошая идиома, чтобы заставить его работать? –

+0

@pengsun: Я предполагаю, что я бы предложил, чтобы попытаться переписать и реорганизовать всю функцию во множество небольших функций. Это руководство по стилю Lua предлагает избегать больших функций, и есть также сообщение в блоге об этом. https://github.com/Olivine-Labs/lua-style-guide#functions Я не думаю, что у lua есть очень хорошая поддержка для создания «макроса включения», как вы вроде как предлагаете. –

1

x переменная, определенная в модуле a.lua не может быть видно из b.lua потому, что он был объявлен как местный. Объем переменной - это собственный модуль.

Если вы хотите x быть видны из b.lua, просто нужно объявить его глобальный. Переменной является либо местный, либо глобальный. Чтобы объявить переменную как global, просто не объявляйте ее local.

a.lua

x = 5 
f = dofile'b.lua' 
f() 

b.lua

local fun = function() 
    print(x) 
end 
return fun 

Это будет работать.

Глобальные переменные живут в глобальном пространстве имен, к которым можно получить доступ в любой момент времени через таблицу _G. Когда Lua не может решить переменную, поскольку она не определена внутри используемого модуля, Lua ищет эту переменную в глобальном пространстве имен. В заключение можно также написать b.lua:

local fun = function() 
    print(_G["x"]) 
end 
return fun 
Смежные вопросы