Love 2D(Lua) 对象中的未预期空值

尝试使用 Lua 和 Love2D ,在 Lua 中遇到了对象实例化/访问的问题。

这里有一个带有 bug 的源码:https://bitbucket.org/dannsee/love_scrollingshooter

在我的主要代码中,我创建了一个对象 Enemies

enemies = Enemies:new()

在 Enemies 对象内部,我创建了一个对象来保存持久值,我称之为 Timers。

timers = Timers:new()

所以 Enemies 的构造方法大致上是这样的

Enemies = {} -- 这样 Enemies 就不会因为 new() 被调用而为 nil
timers = {} -- 这样 timers 就可以在类作用域中访问

function Enemies:new(enemies)
  enemies = enemies or {}
  timers = Timers:new()
  setmetatable(enemies, self)
  self.__index = self
  return enemies
end

而被创建的计时器是这样的

Timers = {} -- 这样 Timers 就不会因为 new() 被调用而为 nil

function Timers:new(timers)
    timers = timers or {
      miniBombTimerMax = 0.2,
      miniBombTimer = minibombTimerMax
    }
    setmetatable(timers, self)
    self.__index = self
    return timers
end

但是,当我尝试引用其中一个计时器(从 Enemies 对象内部)时,我得到了一个空值异常。

timers.miniBombTimer -- 引发空值异常

在我看来,这应该既在作用域内,因为它是在这个类内部创建的对象,并在分配值之前在本地实例化为 timers = {},同时也不应该为 nil,因为它在 ' 构造方法 ' 中被赋予了一个值。但似乎这里发生了更多我没有掌握的事情。

我是 Lua 的新手,这一点可能很明显,但根据我所阅读的有关变量作用域的内容,这应该是有效的。我不明白为什么计时器没有被创建为有值。

点赞
用户1108505
用户1108505

谨慎使用全局变量!在 Lua 中,当你没有意识到时,很容易意外设置全局变量,看起来就像正在发生的那样。

function Enemies:new(enemies)
  enemies = enemies or {}
  timers = Timers:new()
  setmetatable(enemies, self)
  self.__index = self
  return enemies
end

在这里第三行,由于timers在此处不是局部变量,所以这个值最终被放入了一个名为timers的_全局_变量中。如果你想设置enemies的一个属性,你需要明确提到enemies:

function Enemies:new(enemies)
  enemies = enemies or {}
  enemies.timers = Timers:new()
  setmetatable(enemies, self)
  self.__index = self
  return enemies
end

现在,你写道:

但是当我尝试引用其中一个计时器(来自 enemies 对象内),我得到了一个空值例外。

Lua 实际上没有任何关于“在一个对象内部”或“在一个类内部”的概念。在一些语言中,当你在一个类内部编写代码时,所有类成员都在作用域内,可以直接引用它们。Lua 不是这些语言之一;在 Lua 中,如果你想引用“一个类成员”,你需要使用点标记法,显式地说明你要访问的对象。(或者你可以使用“高级方法”,使用 _ENV。)

顺便说一下...

timers = {} -- 以便在类作用域中访问 timers

从问题中我看到,这一行并没有很大的作用;它只是创建了一个从未被使用的全局变量。

还有,在Enemies:new中的这行代码:

self.__index = self

这只是每次调用Enemies:new时设置Enemies.__index。这是_可以_的,但你可以将其设置一次:

function Enemies:new(enemies)
  enemies = enemies or {}
  enemies.timers = Timers:new()
  setmetatable(enemies, self)
  return enemies
end

Enemies.__index = Enemies
2017-08-21 21:19:03