2011-11-23 1 views
5

Есть ли способ иметьРекомендуемый способ иметь 2+ модули рекурсивно ссылаются друг на друга в Lua 5.2

  • Два модуля Lua (назовем их A и B)
  • Каждый модуль использует функции из другие, поэтому они должны require друг другу
  • Третий модуль (назовем его C) может использовать A, но не B например

C.lua:

local A = require 'A' 

-- ... 

A.foo() 
  • Там может быть другой модуль D, который требует B, но не A и/или E, требующий как A и B
  • Ни A ни B, ни их члены должны быть добавлен в глобальное пространство имен.
  • Избегайте использование функции module и setfenv (устаревшее в Lua 5.2)

Связанных: Lua - how do I use one lib from another? (примечание:. Это решение не обрабатывает циклические зависимости)

ответ

5

я нашел довольно простой способ сделать это:

A.lua

local A = {} 
local B 

function A.foo() 
    B = B or require 'B' 
    return B.bar() 
end 

function A.baz() 
    return 42 
end 

return A 

B.lua:

local B = {} 
local A 

function B.bar() 
    A = A or require 'A' 
    return A.baz() 
end 

return B 
+0

Есть ли вред в вызове 'require' из функции вроде этого? Я только видел, как он использовался на верхнем уровне. – finnw

+4

В этом [предупреждении] в [справочном руководстве] (http://www.lua.org/manual/5.1/manual.html#pdf-require), поэтому я считаю, что это безопасно. –

+1

Вы можете использовать 'require' в любом месте кода. Например, я часто использую эту идиому, чтобы запустить RemDebug в заданной точке файла: 'if somecondition then require 'remdebug.engine'.start() end' –

2

Стандартный способ сделать это на любом языке является введение медиатора. Затем модули могут публиковать и подписываться на посредника. http://en.wikipedia.org/wiki/Mediator_pattern

Примером этого на моих языках является mvccontrib bus, IEventAggregator и MVVM Lite Messenger. Все они делают то же самое.

3

Другой метод, предложенный Owen Shepherd на the lua-l mailing list:

Если мы устанавливаем package.loaded[current-module-name] в верхней части каждого модуля, то любой другой модуль require d позже может относиться к текущему (возможно неполному) модулю.

A.lua:

local A = {} 
package.loaded[...] = A 

local B = require 'B' 

function A.foo() 
    return B.bar() 
end 

function A.baz() 
    return 42 
end 

return A 

B.lua:

local B = {} 
package.loaded[...] = B 

local A = require 'A' 

function B.bar() 
    return A.baz() 
end 

return B 

Это не будет работать везде.Например, если инициализация B зависит от A.baz, тогда она не сработает, если сначала загрузится A, потому что B увидит неполную версию A, в которой baz еще не определено.

+0

, если вы не хотите, чтобы вызов требовал все время (в каждая функция, описанная в [finnw] другом решении] (http://stackoverflow.com/a/8248862/1162609)), кажется, что это единственный путь, который нужно оставить. Imho тоже неплохо, так как «return modename» в конце вашего модуля записывается в 'package.loaded [...]' anyway (используя эту структуру не загрязняющего глобального пространства имен и возвращающего таблицы из модулей) –

Смежные вопросы