Lua面向对象编程 - 我不明白如何创建一个“类”的实例?

时间:2014-01-11 05:27:52

标签: oop lua

我正在构建一个简单的游戏,我一直在关注PIL书。以下是我的游戏基础: http://www.lua.org/pil/16.1.html

我很挣扎,因为本书中只有一个模块,我试图让8个模块一起工作。

这是我游戏的一小部分:我现在有一个游戏模块,一个Board模块和一个输入/输出模块。

我以为我知道何时使用冒号以及何时使用句号,但我不明白为什么,在PIL示例中,作者将“o”传递给“new”方法以及为什么有冒号那种方法?

我的游戏模块应该是我的最高级别模块。在其中,我认为我会新增电路板和输入/输出模块并让它们协同工作。但是那些“新”(意思是初始化)方法对于电路板和输入/输出模块看起来是什么样的呢?

这里有一些我一直在使用的代码(简化):

Game = {}

function Game:new(o)
  o = {} or o
  setmetatable(o, self)
  self.__index = self
  -- need board and input_output instances below
  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 {}
  -- need layout attribute here
  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 {}
  -- need read and write attributes here
  o.read = stdin
  o.write = stdout
  setmetatable(o, self)
  self.__index = self
  return o
end

return Input_Output

在像Ruby这样的OOP语言中,Game会保存我的Board和Input_Output类的实例。然后,如果我深入到game.board,我可以看到公共属性和公共方法。

但是,当我在游戏中新建这两个“课程”时,会发生一些奇怪的事情。我的自我和o变量不是我所期望的(我正在使用lua_inspect)。我似乎可能用模块的每个新实例覆盖o变量中的数据?

我迷失了,我认为这是因为“新”方法。我只是没有得到它。

有人可以解释一下吗?我的问题主要是 - 示例中的“o”是什么,为什么“new”方法上有冒号?

3 个答案:

答案 0 :(得分:4)

我试着解释一下。它还将帮助我更深入地理解这一点。

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

Account = {}
function Account:new (o)
  o = o or {}   -- create object if user does not provide one
  setmetatable(o, self)
  self.__index = self
  return o
end

了解Lua中的函数

function foo (x) return 2*x end

只是我们称之为语法糖的一个例子;换句话说,这只是一种很好的写作方式

foo = function (x) return 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

以下发现过程:

Find if there is a 'new' key in `Account`? --Yes-- Return `Account.new`
               |
               No
               |
Check if `Account` has a metatable? --No-- Return `nil`
                |
                Yes
                |
Check if there is a 'new' key in the `__index` field of `Account`'s metatable --No-- Return `nil`
                |
                Yes
                |
    Assume `metaAccount` is the metatable of Account
    Return `metaAccount.__index.new`

Account:new做什么

o = o or {} -- just create a new table if the input o is nil

setmetatable(o, self) -- self is Account because of `:`, and set o's metatable to Account

self.__index = self -- the same as Account.__index = Account, this is set the `__index` field of Account, which is o's metatable

return o --return o, a table which has a metatable `Account`, and `Account` has a `__index` field is also `Account`

如何运作

我们定义另一个函数

function Account:print() --the same as Account.print = function( self )
    print("Class Account.")
end

a = Account:new() --a is a table which has a metatable `Account`, and `Account` has a `__index` field is also `Account`
a:print() --find a.print in a's metatable `Account` as a function, and run it
-->Class Account.

你现在应该清楚......

答案 1 :(得分:2)

实际上Lua中没有“官方”类,所以你可以按照自己想要的方式实现它们。在此特定实现中,o是新实例,可能具有一些预定义参数。它继承了父级的所有成员,无论是值还是方法 - 函数 - 在Lua中都是一样的。如果您在此通话中没有提供o,则会为您创建一个空表。

函数定义中的

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

您应该像local my_game = Game:new()一样调用此函数。之后,my_game将成为包含my_game.boardmy_game.input_output成员的表格。

您当前的问题并不完全清楚您所看到的内容以及它与您的期望有何不同。如果您提供更多详细信息,我也可以添加更多详细信息以供回答。

答案 2 :(得分:1)

所以关注“示例中的'o'是什么,为什么”new“方法上有冒号?”:

所以游戏就是这个类:它是一个有功能的表。这是Lua课堂的基本概念。那么什么是游戏的实例?它是一个表,其metatable是它的类表,即Game。

但是在Lua中,表中的函数无法知道它在哪个表中,除非它将此信息作为调用参数给出。 Lua通过自动引用包含表作为第一个参数来实现这一点很简单用结肠而不是点来调用它时。第一个参数名称为“self”。所以在“new”函数中,用冒号调用它提供了new被定义为self param的表,即类Game。

所以你可以看到'o'是你正在创建的实例,你用冒号调用new,否则你必须给它一个类表,然后在你的语句中出现两次,即冒号提供更好的语法。 / p>