Lua面向对象编程-我不知道如何实例化一个“类”?

我正在制作一个简单的游戏,一直在跟着 PIL 书籍学习。这里是我游戏的基本情境: http://www.lua.org/pil/16.1.html

我面临一个问题,书中只有一个模块,而我正在尝试让8个模块共同工作。

这里是我游戏的一小部分:我目前只有一个游戏模块、一个游戏板模块和一个输入/输出模块。

我原本以为我明白何时使用冒号和何时使用句点,但我不明白 PIL 中的作者为什么要将“o”传递给“new”方法,以及为什么该方法有一个冒号?

我的游戏模块应该是我最高级别的模块。在其中,我认为我应该使用 board 和输入/输出模块的“new”方法,并让它们共同工作。但是,对于板和输入/输出模块,这些“new”(即初始化)方法看起来像什么样子?

这里是我一直在处理的一些代码(简化版本):

Game = {}

function Game:new(o)
  o = {} or o
  setmetatable(o, self)
  self.__index = self
  -- 下面需要 board 和 input_output 实例
  o.board = Board:new(o)
  o.input_output = Input_Output:new(o)
  return o
end

return Game
----------------------------------------------------
Board = {}

function Board:new(o)
  o = o or {}
  -- 这里需要布局属性
  o.layout = { create_layout() }
  setmetatable(o, self)
  self.__index = self
  return o
end

return Board
---------------------------------------------------
Input_Output = {}

function Input_Output:new(o)
  o = o or {}
  -- 这里需要读写属性
  o.read = stdin
  o.write = stdout
  setmetatable(o, self)
  self.__index = self
  return o
end

return Input_Output

在类似 Ruby 的面向对象语言中,游戏会持有我板和输入/输出类的实例。然后,如果我钻到 game.board 中,我可以看到 board 的公共属性和公共方法。

然而,当我在游戏中新建这两个“类”时,有些奇怪的事情发生了。我的 self 和 o 变量不是我预期的(我正在使用 lua_inspect)。每个模块实例似乎可能会覆盖 o 变量中的数据?

我很迷茫,我认为这是因为“new”方法。我就是不明白。

有人能解释一下吗? 我主要的问题是 - 示例中的“o”是怎么回事,并且为什么“new”方法有一个冒号?

点赞
用户936986
用户936986

实际上,Lua 中没有“官方”的类,因此您可以按任何您想要的方式实现它们。在这个特定的实现中,o 是新实例,可能带有一些预定义的参数。它继承了父类的所有成员,包括值或方法(函数) - 在 Lua 中它们都是一样的。如果在此调用中根本不提供 o,则会为您创建一个空表。

函数定义中的 : 只是 function Game.new(self, o) 的语法糖 - 也就是说,它添加了一个名为 self 的第一个参数。

您应该像这样调用这个函数 local my_game = Game:new()。之后,my_game 将成为一个具有 my_game.boardmy_game.input_output 成员的表。

您当前的问题并不是非常清晰,不清楚您看到了什么以及它与您的期望有何不同。如果您提供更多细节,我可以添加更多细节来回答。

2014-01-11 11:54:13
用户1474999
用户1474999

我正在尝试解释这个问题。这也将帮助我更深入地理解这个问题。

因此,只需查看[http://www.lua.org/pil/16.1.html]中的示例。

`` ` Account = {} function Account:new(o)   o = o或{} - 如果用户没有提供,则创建对象   setmetatable(o,self)   self.__index = self   返回o end

`` `

##了解Lua中的函数

`` ` function foo(x)返回2 * x end

`` `

只是我们所说的语法糖的一个实例;换句话说,这只是一种漂亮的写法

`` ` foo = function(x)返回2 * x end

`` `


你知道只是一个的语法设施。

`` ` function Account:new(o)

`` `

`` ` function Account.new(Account,o)

`` `

相同


所以上面,我们知道

`` ` function Account:new(o)

`` `

`` ` Account.new = function(Account,o)

`` `

相同

##如何在Lua表中找到某物

`` ` a = Account.new

`` `

以下是查找过程:

`` 查找Account中是否有“新”键? --是--返回Account.new    |    否    | 检查“Account”是否具有元表? --否--返回    |    是    | 检查Account的元表__index字段中是否有“新”键 --否--返回    |    是    |     假设metaAccount是Account的元表     返回metaAccount.__index.new`

`` `

Account:new作了什么

`` ` o = o或{} - 如果输入的o为nil,则只需创建一个新表

setmetatable(o,self) - 自我是账户,因为“:”,并将o的元表设置为帐户

self.__index = self --与Account.__index = Account相同,这是设置Account的“__index”字段,即o的元表

返回o - 返回o,一个具有元表“Account”的表,而“Account”的“__index”字段也是“Account”

`` `

##它如何工作

我们定义另一个函数

`` ` function Account:print() - 与Account.print = function(self)相同     打印(“类帐户。”) 结束

a = Account:new() - a是一个具有元表“Account”的表,“Account”的“__index”字段也是“Account” a:print() - 在a的元表Account中查找一个函数作为a的打印,并运行它    -> Class Account.

`` `

你现在应该清楚了...

2014-01-11 13:21:18
用户869951
用户869951

所以要关注的是“示例中的'o'是什么意思,为什么“new”方法有一个冒号呢?”:

在Lua中,Game是一个类:它是一个带有函数的表。那么什么是Game的一个实例?它是一个表,其元表是其类的表,即Game。

但是在Lua中,表中的函数无法知道它所在的表,除非在调用参数中提供了这个信息。Lua通过在使用冒号而不是点号调用函数时自动将对包含表的引用作为第一个参数传递给函数,使这个过程变得简单。这个第一个参数的名称为“self”。因此,在“new”函数中,使用冒号调用它会提供new所定义的表作为self参数,即Game类。

因此,您可以看到,“o”是您正在创建的实例,并且您使用冒号来调用new,否则您将不得不将它作为参数提供给class表,这样在您的语句中就会出现两次,即冒号提供更好的语法。

2014-01-11 22:31:27