在名为foo.Lua的Lua文件中,名为self.bar、foo.bar和bar的变量之间的区别是什么?

在名为foo.Lua的Lua文件中,名为self.bar、foo.bar和bar的变量之间的区别是什么?,lua,coronasdk,Lua,Coronasdk,与我的示例类似的是,我正在构建一个游戏,并且有一个名为player.lua的类 几周前我编写了这个代码,当时我不知道Lua是如何工作的,所以我没有为玩家构建一张桌子 我为玩家分配了各种属性,如self.speed或self.strength。我希望(而且它是有效的)这些属性都是玩家的 我有些问题似乎找不到合乎逻辑、直观的答案 如果我在player.lua中声明了一个表(player={}),那么player.speed将引用player表的“speed”键。但如果没有这样一张桌子,我现在到底在做

与我的示例类似的是,我正在构建一个游戏,并且有一个名为player.lua的类

几周前我编写了这个代码,当时我不知道Lua是如何工作的,所以我没有为玩家构建一张桌子

我为玩家分配了各种属性,如self.speed或self.strength。我希望(而且它是有效的)这些属性都是玩家的

我有些问题似乎找不到合乎逻辑、直观的答案

如果我在player.lua中声明了一个表(player={}),那么player.speed将引用player表的“speed”键。但如果没有这样一张桌子,我现在到底在做什么

如果我在player.lua中使用player.speed而不是self.speed呢

如果将来我想在同一个游戏中同时拥有多个玩家怎么办?如何“实例化同一类的多个实例”,就像在Java中,但在Lua中一样?这基本上会包括一个中心游戏lua文件,比如main.lua或game.lua,然后构建一个玩家表,其中每个元素本身就是一个玩家表吗

比如,listofPlayers={} 你会说: insert(listOfPlayers,player:new()),其中player:new()将使用播放器的所有默认属性实例化一个新表,然后返回该表

那么我什么时候使用元表?

元表 元表用于重载语言中的常见操作。这些操作可以包括加法、乘法、相等比较和(顾名思义)类似于表的操作,例如通过键
表[key]
访问值

元表通常用于在Lua中实现面向对象编程。驱动此操作的主要机制是使用
\uu索引
。本例将以最基本的形式说明这一点:

>>> parent = {parentID = 'Secret'}
>>> child = {}
>>> setmetatable(child,{__index=parent})
>>> =child.parentID
Secret
parentID
实际上不存在于child中,因此child中没有类似的东西:

child = {
        parentID = 'Secret'
    }
相反,我们将其设置为当有人查找不存在于
子项
中的键时,我们会在
父项
中查找,这是在元表中设置的,我们在中分配给表:

>>> setmetatable(child,{__index=parent})
因此,当我们请求
child.parentID
时,从编程的角度来看,事件流是:

  • child
    是否包含键为
    “parentID”
    的键、值对?不,因此转到2
  • 子项
    是否在其元表中定义了
    \u索引
    ?是的,去3号
  • 查看
    \uu index
    引用的表以检查键
    “parentID”
  • 在父目录中找到!返回
    parent[“parentID”]
  • 因此,这允许我们在表之间创建关系。我们可以使用
    \u index
    元表方法在表示所有玩家信息的表和每个玩家自身之间建立关系,如下所示:

    Player = { }
        Player_metatable = {
            __index = Player --look for the missing key in the Player table
        }
    
        function Player.new(name)
            aPlayer = { name = name } 
            setmetatable(aPlayer,Player_metatable)
            return aPlayer
        end 
    
        function Player:rotate()
            print("I'M ROTATING",tostring(self))
        end 
    
        henry =  Player.new("Henry")
        henry:rotate()
    
    当我们调用
    Player.new(“Henry”)
    时,我们创建了一个表,并将其元表设置为
    Player\u metatable
    ,就像在第一个示例中设置
    child
    的元表一样。然而,我们只是在一个函数中进行,而不是在球棒的直线上进行,没有区别

    当我们调用
    henry:rotate()
    时,如上所述的情况是:我们在
    henry
    中查找一个键
    “rotate”
    ,但没有找到,所以我们在
    Player
    中查找(因为在我们的元表中,
    \u index
    指向该表)。这里有一个与该键相关的函数。然后我们调用这个函数,因为
    t:function
    语法将我们自己传递进来

    要创建类的实例,只需指定一个表,即指向定义类行为的表的元表。因此,我们可以创建任意数量的玩家:

    my_player_name = Player.new(...)
    

    修改
    Player
    表中的值将反映在具有关联元表的所有表中。

    从其他类继承的另一种方法是复制所有方法,可能通过“new”方法。在这是你可以混合和匹配从许多类。 Lua只需复制对该方法的引用,因此内存开销最小

    prototype={}
    --add some methods to prototype
    function prototype:new()
     local newtable={}
     for k,v in pairs(self) do
       newtabke[k]=v
     end
     return newtable
    end
    

    HennyH很好地描述了元表是如何使用的,以及它们给了您什么,但是为了直接回答您的问题,假设您的播放器表包含一个方法
    name

    local Player = {}
    local name
    function Player:name()
      return self.name -- #1
      return Player.name -- #2
      return name -- #3
    end
    
    • #1使用
      self
      表的
      name
      字段,这是您大部分时间使用的,因为它允许使用元表来实现类继承
      self
      将引用调用的任何表
      name
      方法(如果该方法是通过
      \u index
      引用找到的,则可能不是
      Player
    • #2使用
      Player
      表的
      name
      字段,忽略对实际
      self
      对象的任何引用。如果您想拥有一些不受继承类影响的特定于播放器的数据,这可能很有用
    • #3使用局部变量。它在许多方面与Player.name类似,但有一个显著的区别:它允许您实现“类”的私有元素。请注意,一些使用
      Player
      类的代码可以随意访问和修改
      Player.name
      。当此方法作为访问
      name
      的唯一方法(当它是一个局部变量时)使用时,情况并非如此,而是通过将此变量作为upvalue的闭包。如果您不提供修改它的方法,它将是只读的

    每个选项都有自己的用途,但#1可能是您最常看到的;您可能希望提到,如果在步骤4中找不到键,那么将检查父级的元表,以便可以对其进行链接