2011-11-23 7 views
5

¿Hay una manera de tenerforma recomendada para tener 2+ módulos de forma recursiva se refieren el uno al otro en Lua 5.2

  • Dos módulos de Lua (llamémosles A y B)
  • Cada módulo utiliza las funciones de la otros, entonces deben require entre ellos
  • Un tercer módulo (llamémoslo C) puede usar A pero no B por ej.

C.lua:

local A = require 'A' 

-- ... 

A.foo() 
  • Puede haber otro módulo D que requiere B pero no A y/o E que requiere tanto A y B
  • Ni A ni B ni sus miembros deben estar agregado al espacio de nombres global.
  • Evitar el uso de las funciones module y setfenv (obsoleto en Lua 5,2)

relacionados: Lua - how do I use one lib from another? (nota:. Esta solución no maneja dependencias circulares)

Respuesta

5

me encontré con un buen forma simple de hacerlo:

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

¿Hay algún problema al llamar 'require' desde una función como esta? Solo lo he visto usado en el nivel superior. – finnw

+4

No hay ninguna advertencia en el [manual de referencia] (http://www.lua.org/manual/5.1/manual.html#pdf-require) al respecto, por lo que creo que es seguro. –

+1

Puede usar 'require' en cualquier parte del código. Por ejemplo, a menudo uso este modismo para iniciar el RemDebug en un punto dado del archivo: 'si alguna condición requiere 'remdebug.engine'.start() end' –

2

Una forma estándar de hacer esto en cualquier idioma es introducir un mediador. Los módulos pueden publicar y suscribirse al mediador. http://en.wikipedia.org/wiki/Mediator_pattern

Un ejemplo de esto en mis idiomas es el bus mvccontrib, IEventAggregator y la clase MVVM Lite Messenger. Todos hacen lo mismo.

3

Otro método, sugerido por Owen Shepherd en the lua-l mailing list:

Si fijamos package.loaded[current-module-name] en la parte superior de cada módulo, a continuación, cualquier otro módulo de require d después puede referirse al módulo actual (posiblemente incompleta).

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 

Esto no funcionará en todas partes.Por ejemplo, si la inicialización de B depende de A.baz, fallará si se carga primero A, porque B verá una versión incompleta de A en la que baz aún no está definido.

+0

si no desea llamar requiere todo el tiempo (en cada función como se describe en [finnw 'otra solución] (http://stackoverflow.com/a/8248862/1162609)), parece que este es el único camino que queda por recorrer. Imho también es bastante agradable ya que el 'return modename' al final de tu módulo se escribe en' package.loaded [...] 'anyway (usando esta estructura de espacio de nombres global no contaminante y devolviendo tablas de módulos) –

Cuestiones relacionadas