【问题标题】:Division of metatable元表的划分
【发布时间】:2014-02-14 11:08:20
【问题描述】:

metatable 有一些问题。这是我的简单元表:

local mt = {}  
function mt:add(n)  
  return setmetatable({n = n}, {__index = mt})  
end

function mt:get() return self.n end

现在我想添加一些部门,例如:

mt.math
mt.effect

每个人都有一些自己的方法,例如:

mt.math:floor() return math.floor(self:get()) end
mt.effect:show(args) onMapShowEffect(self:get(), {x = x + (args[1] ~= nil or 0), ...) end
mt.effect:get() return getCurrentPos() end

有什么想法吗?

好的,尝试制作所有细节以分享我的问题。

Player = {}  
function Player:add(this)
  return setmetatable({this = this}, {__index = Player})
end

Player:get() return self.this end

以上代码在本例中完美运行

function enterToGame(player1, player2)
  local p1 = Player:add(player1)
  local p2 = Player:add(player2)
  print(p1:get()) -- ID1
  print(p2:get()) -- ID2

现在我想为桌面播放器创建一些有用的方法(函数)。我想让它更灵活,所以我想把它划分为类。示例:

Player.info = {
  id = function() return Player:get() end,
}
Player.pos = {
  get = function() return getPosition(Player:get()) end,
  set = function(args) setPosition(Player:get(), args) end,
}
Player.speed = {
  get = function() return getSpeed(Player:get()) end,
  set = function(value) setSpeed(value) end,
  improve = function(value) setSpeed(Player.speed.get() + value) end,
}

但它并不完全符合我的要求:

function enterToGame(player1, player2)
  local p1 = Player:add(player1)
  local p2 = Player:add(player2)
  print(p1:get()) -- ID1
  print(p2:get()) -- ID2
  print(p1.info.id()) -- ID2 instead of ID1
  print(p2.info.id()) -- ID2

当我将 Player:get() 放入我的方法中时,它会返回最后一个对象声明。

【问题讨论】:

  • 我不确定我是否完全理解这个问题,但这些内部函数中的 self 将是 mt.math/mt.effect 表,而不是顶级 mt 表您不清楚的情况。
  • 有什么方法可以调用mt吗?
  • 如果你给你的 mt 表一个 __call 元方法,它可以被调用。不过,我不确定这与您的问题有什么关系。

标签: lua metaclass lua-table


【解决方案1】:

根据你所说的,如果你这样做了

mt.math = mt:add(123)

您不需要mt:get(),因为 mt 是 mt.math 的元表。那么

mt.math.floor = function(self) return math.floor(self.n) end

将按预期工作。例如,

print(mt.math:floor())

打印 123。

编辑1:所以现在我对你想要做的事情有了更好的理解:通常你会这样做

p1:id()
p1:getPos()
p1:setPos()
p1:getSpeed()
p1:improveSpeed()

注意冒号,这很重要,这样每个方法都会获得一个“self”作为第一个参数,从而为它们提供要操作的表实例(p1,在上面的示例中)。相反,您想对方法进行分组

p1.info:id()
p1.pos:get()
p1.pos:set()
p1.speed:improve()
p1.speed:get()

这些方法会得到一个指向p1.info、p1.pos等的self。但是那些子表不知道容器表(p1)。 info 和 pos 表在 Player 类中:它们由 Player 的所有实例(p1、p2 等)共享。您必须使 info 和 pos 表不共享:

function Player:add(player) 
    local pN= setmetatable( {n = player, info={}, pos={}}, {__index = Player})  
    pN.info.id = function() return pN.n end 
    pN.pos.set = function(x) return setPosition(pN, x) end
    return pN
end

然后你得到

> p1=mt:add(player1)
> p2=mt:add(player2)
> print(player1)
table: 0024D390
> print(p1.info.id())
table: 0024D390
> print(player2)
table: 0024D250
> print(p2.info.id())
table: 0024D250

话虽如此,我真的不喜欢必须使用这样的闭包的想法,也许有一些陷阱,因为并非所有东西都会在 Player 中。

【讨论】:

  • 不完全是这样。我想在使用之前创建函数。在您的情况下,我需要首先将mt:add() 分配给mt.math,然后创建函数mt.math.floor。编辑我的问题以获取更多详细信息。
  • @user3225882 好的,我根据你的新信息扩展了答案我想我明白你现在想要做什么
猜你喜欢
  • 2020-03-27
  • 1970-01-01
  • 2022-01-13
  • 2017-12-14
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-19
相关资源
最近更新 更多