简体   繁体   中英

Lua 5.2 metatables and environment

I've got a structure like this:

context = {
  pi = math.pi,
  sin = math.sin,
  cos = math.cos,
  tan = math.tan,
  print = print
}

modules = {
  m1 = {
    variables = { x = 1 },
    update = function(self)
      local _ENV = self.variables
      x = 2
      m2.x = 2
    end
  },
  m2 = {
    variables = { x = 1 },
    update = function(self)
      local _ENV = self.variables
    end
  }
}

setmetatable(modules.m1, {__index = modules.m1.variables})
setmetatable(modules.m1.variables, {__index = context})

setmetatable(modules.m2, {__index = modules.m2.variables})
setmetatable(modules.m2.variables, {__index = context})

setmetatable(context, {__index = modules})

The idea is that users enter code into a UI and that code is pasted into the update functions of the different modules, just after where local _ENV is set. This user-entered code should be sandboxed. It should be able to access a few functions (the ones in the context table) and the contents of other modules. Code in m1:update should be able to refer to variables in m1.variables without qualifying them; variables in other modules (ie ones in m2.variables ) should be accessible by qualifying them with the module name (ie m2.x ).

But the result I get is this:

$ lua -i test.lua
> = modules.m1.x
1
> = modules.m1.variables.x
1
> = modules.m2.x
1
> = modules.m2.variables.x
1
> = modules.m1:update()
> = modules.m1.x
2
> = modules.m1.variables.x
2
> = modules.m2.x
2
> = modules.m2.variables.x
1

Why is modules.m2.variables.x not getting updated? And if, as it seems, modules.m2.x is different to modules.m2.variables.x , then where is modules.m2.x coming from?

modules.m2.variables.x is not getting updated because you only set __index metamethod (which is used when retrieving a non-existing key), but not __newindex metamethod (which is used when assigning a value to a non-existent key), and as the result the value is stored in modules.m2.x table and not modules.m2.variables.x table as you intended.

If I add __newindex as in setmetatable(modules.m2, {__index = modules.m2.variables, __newindex = modules.m2.variables}) , I get the expected result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM